js_generator.cc
Go to the documentation of this file.
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 
32 
33 #include <assert.h>
34 #include <algorithm>
35 #include <limits>
36 #include <map>
37 #include <memory>
38 #include <string>
39 #include <utility>
40 #include <vector>
41 
46 
53 
54 
55 namespace google {
56 namespace protobuf {
57 namespace compiler {
58 namespace js {
59 
60 // Sorted list of JavaScript keywords. These cannot be used as names. If they
61 // appear, we prefix them with "pb_".
62 const char* kKeyword[] = {
63  "abstract", "boolean", "break", "byte", "case",
64  "catch", "char", "class", "const", "continue",
65  "debugger", "default", "delete", "do", "double",
66  "else", "enum", "export", "extends", "false",
67  "final", "finally", "float", "for", "function",
68  "goto", "if", "implements", "import", "in",
69  "instanceof", "int", "interface", "long", "native",
70  "new", "null", "package", "private", "protected",
71  "public", "return", "short", "static", "super",
72  "switch", "synchronized", "this", "throw", "throws",
73  "transient", "try", "typeof", "var", "void",
74  "volatile", "while", "with",
75 };
76 
77 static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*);
78 
79 namespace {
80 
81 // The mode of operation for bytes fields. Historically JSPB always carried
82 // bytes as JS {string}, containing base64 content by convention. With binary
83 // and proto3 serialization the new convention is to represent it as binary
84 // data in Uint8Array. See b/26173701 for background on the migration.
85 enum BytesMode {
86  BYTES_DEFAULT, // Default type for getBytesField to return.
87  BYTES_B64, // Explicitly coerce to base64 string where needed.
88  BYTES_U8, // Explicitly coerce to Uint8Array where needed.
89 };
90 
91 bool IsReserved(const std::string& ident) {
92  for (int i = 0; i < kNumKeyword; i++) {
93  if (ident == kKeyword[i]) {
94  return true;
95  }
96  }
97  return false;
98 }
99 
100 bool StrEndsWith(StringPiece sp, StringPiece x) {
101  return sp.size() >= x.size() && sp.substr(sp.size() - x.size()) == x;
102 }
103 
104 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto
105 // suffix stripped.
106 // TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc.
107 std::string StripProto(const std::string& filename) {
108  const char* suffix =
109  StrEndsWith(filename, ".protodevel") ? ".protodevel" : ".proto";
110  return StripSuffixString(filename, suffix);
111 }
112 
113 std::string GetSnakeFilename(const std::string& filename) {
114  std::string snake_name = filename;
115  ReplaceCharacters(&snake_name, "/", '_');
116  return snake_name;
117 }
118 
119 // Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript
120 // file foo/bar/baz.js.
121 std::string GetJSFilename(const GeneratorOptions& options,
122  const std::string& filename) {
123  return StripProto(filename) + options.GetFileNameExtension();
124 }
125 
126 // Given a filename like foo/bar/baz.proto, returns the root directory
127 // path ../../
128 string GetRootPath(const std::string& from_filename,
129  const std::string& to_filename) {
130  if (to_filename.find("google/protobuf") == 0) {
131  // Well-known types (.proto files in the google/protobuf directory) are
132  // assumed to come from the 'google-protobuf' npm package. We may want to
133  // generalize this exception later by letting others put generated code in
134  // their own npm packages.
135  return "google-protobuf/";
136  }
137 
138  size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');
139  if (slashes == 0) {
140  return "./";
141  }
142  std::string result = "";
143  for (size_t i = 0; i < slashes; i++) {
144  result += "../";
145  }
146  return result;
147 }
148 
149 // Returns the alias we assign to the module of the given .proto filename
150 // when importing.
151 std::string ModuleAlias(const std::string& filename) {
152  // This scheme could technically cause problems if a file includes any 2 of:
153  // foo/bar_baz.proto
154  // foo_bar_baz.proto
155  // foo_bar/baz.proto
156  //
157  // We'll worry about this problem if/when we actually see it. This name isn't
158  // exposed to users so we can change it later if we need to.
159  std::string basename = StripProto(filename);
160  ReplaceCharacters(&basename, "-", '$');
161  ReplaceCharacters(&basename, "/", '_');
162  ReplaceCharacters(&basename, ".", '_');
163  return basename + "_pb";
164 }
165 
166 // Returns the fully normalized JavaScript namespace for the given
167 // file descriptor's package.
168 std::string GetNamespace(const GeneratorOptions& options,
169  const FileDescriptor* file) {
170  if (!options.namespace_prefix.empty()) {
171  return options.namespace_prefix;
172  } else if (!file->package().empty()) {
173  return "proto." + file->package();
174  } else {
175  return "proto";
176  }
177 }
178 
179 // Returns the name of the message with a leading dot and taking into account
180 // nesting, for example ".OuterMessage.InnerMessage", or returns empty if
181 // descriptor is null. This function does not handle namespacing, only message
182 // nesting.
183 std::string GetNestedMessageName(const Descriptor* descriptor) {
184  if (descriptor == NULL) {
185  return "";
186  }
188  descriptor->full_name(), descriptor->file()->package());
189  // Add a leading dot if one is not already present.
190  if (!result.empty() && result[0] != '.') {
191  result = "." + result;
192  }
193  return result;
194 }
195 
196 // Returns the path prefix for a message or enumeration that
197 // lives under the given file and containing type.
198 std::string GetPrefix(const GeneratorOptions& options,
199  const FileDescriptor* file_descriptor,
200  const Descriptor* containing_type) {
201  std::string prefix = GetNamespace(options, file_descriptor) +
202  GetNestedMessageName(containing_type);
203  if (!prefix.empty()) {
204  prefix += ".";
205  }
206  return prefix;
207 }
208 
209 // Returns the fully normalized JavaScript path prefix for the given
210 // message descriptor.
211 std::string GetMessagePathPrefix(const GeneratorOptions& options,
212  const Descriptor* descriptor) {
213  return GetPrefix(options, descriptor->file(), descriptor->containing_type());
214 }
215 
216 // Returns the fully normalized JavaScript path for the given
217 // message descriptor.
218 std::string GetMessagePath(const GeneratorOptions& options,
219  const Descriptor* descriptor) {
220  return GetMessagePathPrefix(options, descriptor) + descriptor->name();
221 }
222 
223 // Returns the fully normalized JavaScript path prefix for the given
224 // enumeration descriptor.
225 std::string GetEnumPathPrefix(const GeneratorOptions& options,
227  return GetPrefix(options, enum_descriptor->file(),
228  enum_descriptor->containing_type());
229 }
230 
231 // Returns the fully normalized JavaScript path for the given
232 // enumeration descriptor.
233 std::string GetEnumPath(const GeneratorOptions& options,
235  return GetEnumPathPrefix(options, enum_descriptor) + enum_descriptor->name();
236 }
237 
238 std::string MaybeCrossFileRef(const GeneratorOptions& options,
239  const FileDescriptor* from_file,
240  const Descriptor* to_message) {
241  if ((options.import_style == GeneratorOptions::kImportCommonJs ||
243  from_file != to_message->file()) {
244  // Cross-file ref in CommonJS needs to use the module alias instead of
245  // the global name.
246  return ModuleAlias(to_message->file()->name()) +
247  GetNestedMessageName(to_message->containing_type()) + "." +
248  to_message->name();
249  } else {
250  // Within a single file we use a full name.
251  return GetMessagePath(options, to_message);
252  }
253 }
254 
255 std::string SubmessageTypeRef(const GeneratorOptions& options,
256  const FieldDescriptor* field) {
258  return MaybeCrossFileRef(options, field->file(), field->message_type());
259 }
260 
261 // - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
262 // (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
263 // and with reserved words triggering a "pb_" prefix.
264 // - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields
265 // (use the name directly), then append "List" if appropriate, then append "$"
266 // if resulting name is equal to a reserved word.
267 // - Enums: just uppercase.
268 
269 // Locale-independent version of ToLower that deals only with ASCII A-Z.
270 char ToLowerASCII(char c) {
271  if (c >= 'A' && c <= 'Z') {
272  return (c - 'A') + 'a';
273  } else {
274  return c;
275  }
276 }
277 
278 std::vector<std::string> ParseLowerUnderscore(const std::string& input) {
279  std::vector<std::string> words;
280  std::string running = "";
281  for (int i = 0; i < input.size(); i++) {
282  if (input[i] == '_') {
283  if (!running.empty()) {
284  words.push_back(running);
285  running.clear();
286  }
287  } else {
288  running += ToLowerASCII(input[i]);
289  }
290  }
291  if (!running.empty()) {
292  words.push_back(running);
293  }
294  return words;
295 }
296 
297 std::vector<std::string> ParseUpperCamel(const std::string& input) {
298  std::vector<std::string> words;
299  std::string running = "";
300  for (int i = 0; i < input.size(); i++) {
301  if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) {
302  words.push_back(running);
303  running.clear();
304  }
305  running += ToLowerASCII(input[i]);
306  }
307  if (!running.empty()) {
308  words.push_back(running);
309  }
310  return words;
311 }
312 
313 std::string ToLowerCamel(const std::vector<std::string>& words) {
314  std::string result;
315  for (int i = 0; i < words.size(); i++) {
316  std::string word = words[i];
317  if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) {
318  word[0] = (word[0] - 'A') + 'a';
319  } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) {
320  word[0] = (word[0] - 'a') + 'A';
321  }
322  result += word;
323  }
324  return result;
325 }
326 
327 std::string ToUpperCamel(const std::vector<std::string>& words) {
328  std::string result;
329  for (int i = 0; i < words.size(); i++) {
330  std::string word = words[i];
331  if (word[0] >= 'a' && word[0] <= 'z') {
332  word[0] = (word[0] - 'a') + 'A';
333  }
334  result += word;
335  }
336  return result;
337 }
338 
339 // Based on code from descriptor.cc (Thanks Kenton!)
340 // Uppercases the entire string, turning ValueName into
341 // VALUENAME.
342 std::string ToEnumCase(const std::string& input) {
343  std::string result;
344  result.reserve(input.size());
345 
346  for (int i = 0; i < input.size(); i++) {
347  if ('a' <= input[i] && input[i] <= 'z') {
348  result.push_back(input[i] - 'a' + 'A');
349  } else {
350  result.push_back(input[i]);
351  }
352  }
353 
354  return result;
355 }
356 
358  std::string result;
359  result.reserve(input.size());
360 
361  for (int i = 0; i < input.size(); i++) {
362  if ('A' <= input[i] && input[i] <= 'Z') {
363  result.push_back(input[i] - 'A' + 'a');
364  } else {
365  result.push_back(input[i]);
366  }
367  }
368 
369  return result;
370 }
371 
372 // When we're generating one output file per SCC, this is the filename
373 // that top-level extensions should go in.
374 // e.g. one proto file (test.proto):
375 // package a;
376 // extends Foo {
377 // ...
378 // }
379 // If "with_filename" equals true, the extension filename will be
380 // "proto.a_test_extensions.js", otherwise will be "proto.a.js"
381 std::string GetExtensionFileName(const GeneratorOptions& options,
382  const FileDescriptor* file,
383  bool with_filename) {
384  std::string snake_name = StripProto(GetSnakeFilename(file->name()));
385  return options.output_dir + "/" + ToLower(GetNamespace(options, file)) +
386  (with_filename ? ("_" + snake_name + "_extensions") : "") +
387  options.GetFileNameExtension();
388 }
389 // When we're generating one output file per SCC, this is the filename
390 // that all messages in the SCC should go in.
391 // If with_package equals true, filename will have package prefix,
392 // If the filename length is longer than 200, the filename will be the
393 // SCC's proto filename with suffix "_long_sccs_(index)" (if with_package equals
394 // true it still has package prefix)
395 std::string GetMessagesFileName(const GeneratorOptions& options, const SCC* scc,
396  bool with_package) {
397  static std::map<const Descriptor*, std::string>* long_name_dict =
398  new std::map<const Descriptor*, std::string>();
399  std::string package_base =
400  with_package
401  ? ToLower(GetNamespace(options, scc->GetRepresentative()->file()) +
402  "_")
403  : "";
404  std::string filename_base = "";
405  std::vector<std::string> all_message_names;
406  for (auto one_desc : scc->descriptors) {
407  if (one_desc->containing_type() == nullptr) {
408  all_message_names.push_back(ToLower(one_desc->name()));
409  }
410  }
411  sort(all_message_names.begin(), all_message_names.end());
412  for (auto one_message : all_message_names) {
413  if (!filename_base.empty()) {
414  filename_base += "_";
415  }
416  filename_base += one_message;
417  }
418  if (filename_base.size() + package_base.size() > 200) {
419  if ((*long_name_dict).find(scc->GetRepresentative()) ==
420  (*long_name_dict).end()) {
421  std::string snake_name = StripProto(
422  GetSnakeFilename(scc->GetRepresentative()->file()->name()));
423  (*long_name_dict)[scc->GetRepresentative()] =
424  StrCat(snake_name, "_long_sccs_",
425  static_cast<uint64>((*long_name_dict).size()));
426  }
427  filename_base = (*long_name_dict)[scc->GetRepresentative()];
428  }
429  return options.output_dir + "/" + package_base + filename_base +
430  options.GetFileNameExtension();
431 }
432 
433 // When we're generating one output file per type name, this is the filename
434 // that a top-level enum should go in.
435 // If with_package equals true, filename will have package prefix.
436 std::string GetEnumFileName(const GeneratorOptions& options,
437  const EnumDescriptor* desc, bool with_package) {
438  return options.output_dir + "/" +
439  (with_package ? ToLower(GetNamespace(options, desc->file()) + "_")
440  : "") +
441  ToLower(desc->name()) + options.GetFileNameExtension();
442 }
443 
444 // Returns the message/response ID, if set.
445 std::string GetMessageId(const Descriptor* desc) {
446  return std::string();
447 }
448 
449 bool IgnoreExtensionField(const FieldDescriptor* field) {
450  // Exclude descriptor extensions from output "to avoid clutter" (from original
451  // codegen).
452  if (!field->is_extension()) return false;
453  const FileDescriptor* file = field->containing_type()->file();
454  return file->name() == "net/proto2/proto/descriptor.proto" ||
455  file->name() == "google/protobuf/descriptor.proto";
456 }
457 
458 
459 // Used inside Google only -- do not remove.
460 bool IsResponse(const Descriptor* desc) { return false; }
461 
462 bool IgnoreField(const FieldDescriptor* field) {
463  return IgnoreExtensionField(field);
464 }
465 
466 
467 // Do we ignore this message type?
468 bool IgnoreMessage(const Descriptor* d) { return d->options().map_entry(); }
469 
470 // Does JSPB ignore this entire oneof? True only if all fields are ignored.
471 bool IgnoreOneof(const OneofDescriptor* oneof) {
472  for (int i = 0; i < oneof->field_count(); i++) {
473  if (!IgnoreField(oneof->field(i))) {
474  return false;
475  }
476  }
477  return true;
478 }
479 
480 std::string JSIdent(const GeneratorOptions& options,
481  const FieldDescriptor* field, bool is_upper_camel,
482  bool is_map, bool drop_list) {
483  std::string result;
484  if (field->type() == FieldDescriptor::TYPE_GROUP) {
485  result = is_upper_camel
486  ? ToUpperCamel(ParseUpperCamel(field->message_type()->name()))
487  : ToLowerCamel(ParseUpperCamel(field->message_type()->name()));
488  } else {
489  result = is_upper_camel ? ToUpperCamel(ParseLowerUnderscore(field->name()))
490  : ToLowerCamel(ParseLowerUnderscore(field->name()));
491  }
492  if (is_map || field->is_map()) {
493  // JSPB-style or proto3-style map.
494  result += "Map";
495  } else if (!drop_list && field->is_repeated()) {
496  // Repeated field.
497  result += "List";
498  }
499  return result;
500 }
501 
502 std::string JSObjectFieldName(const GeneratorOptions& options,
503  const FieldDescriptor* field) {
504  std::string name = JSIdent(options, field,
505  /* is_upper_camel = */ false,
506  /* is_map = */ false,
507  /* drop_list = */ false);
508  if (IsReserved(name)) {
509  name = "pb_" + name;
510  }
511  return name;
512 }
513 
514 std::string JSByteGetterSuffix(BytesMode bytes_mode) {
515  switch (bytes_mode) {
516  case BYTES_DEFAULT:
517  return "";
518  case BYTES_B64:
519  return "B64";
520  case BYTES_U8:
521  return "U8";
522  default:
523  assert(false);
524  }
525  return "";
526 }
527 
528 // Returns the field name as a capitalized portion of a getter/setter method
529 // name, e.g. MyField for .getMyField().
530 std::string JSGetterName(const GeneratorOptions& options,
531  const FieldDescriptor* field,
532  BytesMode bytes_mode = BYTES_DEFAULT,
533  bool drop_list = false) {
534  std::string name = JSIdent(options, field,
535  /* is_upper_camel = */ true,
536  /* is_map = */ false, drop_list);
537  if (field->type() == FieldDescriptor::TYPE_BYTES) {
538  std::string suffix = JSByteGetterSuffix(bytes_mode);
539  if (!suffix.empty()) {
540  name += "_as" + suffix;
541  }
542  }
543  if (name == "Extension" || name == "JsPbMessageId") {
544  // Avoid conflicts with base-class names.
545  name += "$";
546  }
547  return name;
548 }
549 
550 
551 std::string JSOneofName(const OneofDescriptor* oneof) {
552  return ToUpperCamel(ParseLowerUnderscore(oneof->name()));
553 }
554 
555 // Returns the index corresponding to this field in the JSPB array (underlying
556 // data storage array).
557 std::string JSFieldIndex(const FieldDescriptor* field) {
558  // Determine whether this field is a member of a group. Group fields are a bit
559  // wonky: their "containing type" is a message type created just for the
560  // group, and that type's parent type has a field with the group-message type
561  // as its message type and TYPE_GROUP as its field type. For such fields, the
562  // index we use is relative to the field number of the group submessage field.
563  // For all other fields, we just use the field number.
564  const Descriptor* containing_type = field->containing_type();
565  const Descriptor* parent_type = containing_type->containing_type();
566  if (parent_type != NULL) {
567  for (int i = 0; i < parent_type->field_count(); i++) {
568  if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP &&
569  parent_type->field(i)->message_type() == containing_type) {
570  return StrCat(field->number() - parent_type->field(i)->number());
571  }
572  }
573  }
574  return StrCat(field->number());
575 }
576 
577 std::string JSOneofIndex(const OneofDescriptor* oneof) {
578  int index = -1;
579  for (int i = 0; i < oneof->containing_type()->oneof_decl_count(); i++) {
580  const OneofDescriptor* o = oneof->containing_type()->oneof_decl(i);
581  // If at least one field in this oneof is not JSPB-ignored, count the oneof.
582  for (int j = 0; j < o->field_count(); j++) {
583  const FieldDescriptor* f = o->field(j);
584  if (!IgnoreField(f)) {
585  index++;
586  break; // inner loop
587  }
588  }
589  if (o == oneof) {
590  break;
591  }
592  }
593  return StrCat(index);
594 }
595 
596 // Decodes a codepoint in \x0000 -- \xFFFF.
597 uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
598  if (*length == 0) {
599  return 0;
600  }
601  size_t expected = 0;
602  if ((*bytes & 0x80) == 0) {
603  expected = 1;
604  } else if ((*bytes & 0xe0) == 0xc0) {
605  expected = 2;
606  } else if ((*bytes & 0xf0) == 0xe0) {
607  expected = 3;
608  } else {
609  // Too long -- don't accept.
610  *length = 0;
611  return 0;
612  }
613 
614  if (*length < expected) {
615  // Not enough bytes -- don't accept.
616  *length = 0;
617  return 0;
618  }
619 
620  *length = expected;
621  switch (expected) {
622  case 1:
623  return bytes[0];
624  case 2:
625  return ((bytes[0] & 0x1F) << 6) | ((bytes[1] & 0x3F) << 0);
626  case 3:
627  return ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) |
628  ((bytes[2] & 0x3F) << 0);
629  default:
630  return 0;
631  }
632 }
633 
634 // Escapes the contents of a string to be included within double-quotes ("") in
635 // JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
636 // Returns false if |out| was truncated because |in| contained invalid UTF-8 or
637 // codepoints outside the BMP.
638 // TODO(b/115551870): Support codepoints outside the BMP.
639 bool EscapeJSString(const std::string& in, std::string* out) {
640  size_t decoded = 0;
641  for (size_t i = 0; i < in.size(); i += decoded) {
642  uint16 codepoint = 0;
643  // Decode the next UTF-8 codepoint.
644  size_t have_bytes = in.size() - i;
645  uint8 bytes[3] = {
646  static_cast<uint8>(in[i]),
647  static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
648  static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
649  };
650  codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
651  if (have_bytes == 0) {
652  return false;
653  }
654  decoded = have_bytes;
655 
656  switch (codepoint) {
657  case '\'':
658  *out += "\\x27";
659  break;
660  case '"':
661  *out += "\\x22";
662  break;
663  case '<':
664  *out += "\\x3c";
665  break;
666  case '=':
667  *out += "\\x3d";
668  break;
669  case '>':
670  *out += "\\x3e";
671  break;
672  case '&':
673  *out += "\\x26";
674  break;
675  case '\b':
676  *out += "\\b";
677  break;
678  case '\t':
679  *out += "\\t";
680  break;
681  case '\n':
682  *out += "\\n";
683  break;
684  case '\f':
685  *out += "\\f";
686  break;
687  case '\r':
688  *out += "\\r";
689  break;
690  case '\\':
691  *out += "\\\\";
692  break;
693  default:
694  // TODO(b/115551870): Once we're supporting codepoints outside the BMP,
695  // use a single Unicode codepoint escape if the output language is
696  // ECMAScript 2015 or above. Otherwise, use a surrogate pair.
697  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals
698  if (codepoint >= 0x20 && codepoint <= 0x7e) {
699  *out += static_cast<char>(codepoint);
700  } else if (codepoint >= 0x100) {
701  *out += StringPrintf("\\u%04x", codepoint);
702  } else {
703  *out += StringPrintf("\\x%02x", codepoint);
704  }
705  break;
706  }
707  }
708  return true;
709 }
710 
711 std::string EscapeBase64(const std::string& in) {
712  static const char* kAlphabet =
713  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
714  std::string result;
715 
716  for (size_t i = 0; i < in.size(); i += 3) {
717  int value = (in[i] << 16) | (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) |
718  (((i + 2) < in.size()) ? (in[i + 2] << 0) : 0);
719  result += kAlphabet[(value >> 18) & 0x3f];
720  result += kAlphabet[(value >> 12) & 0x3f];
721  if ((i + 1) < in.size()) {
722  result += kAlphabet[(value >> 6) & 0x3f];
723  } else {
724  result += '=';
725  }
726  if ((i + 2) < in.size()) {
727  result += kAlphabet[(value >> 0) & 0x3f];
728  } else {
729  result += '=';
730  }
731  }
732 
733  return result;
734 }
735 
736 // Post-process the result of SimpleFtoa/SimpleDtoa to *exactly* match the
737 // original codegen's formatting (which is just .toString() on java.lang.Double
738 // or java.lang.Float).
739 std::string PostProcessFloat(std::string result) {
740  // If inf, -inf or nan, replace with +Infinity, -Infinity or NaN.
741  if (result == "inf") {
742  return "Infinity";
743  } else if (result == "-inf") {
744  return "-Infinity";
745  } else if (result == "nan") {
746  return "NaN";
747  }
748 
749  // If scientific notation (e.g., "1e10"), (i) capitalize the "e", (ii)
750  // ensure that the mantissa (portion prior to the "e") has at least one
751  // fractional digit (after the decimal point), and (iii) strip any unnecessary
752  // leading zeroes and/or '+' signs from the exponent.
753  std::string::size_type exp_pos = result.find('e');
754  if (exp_pos != std::string::npos) {
755  std::string mantissa = result.substr(0, exp_pos);
756  std::string exponent = result.substr(exp_pos + 1);
757 
758  // Add ".0" to mantissa if no fractional part exists.
759  if (mantissa.find('.') == std::string::npos) {
760  mantissa += ".0";
761  }
762 
763  // Strip the sign off the exponent and store as |exp_neg|.
764  bool exp_neg = false;
765  if (!exponent.empty() && exponent[0] == '+') {
766  exponent = exponent.substr(1);
767  } else if (!exponent.empty() && exponent[0] == '-') {
768  exp_neg = true;
769  exponent = exponent.substr(1);
770  }
771 
772  // Strip any leading zeroes off the exponent.
773  while (exponent.size() > 1 && exponent[0] == '0') {
774  exponent = exponent.substr(1);
775  }
776 
777  return mantissa + "E" + string(exp_neg ? "-" : "") + exponent;
778  }
779 
780  // Otherwise, this is an ordinary decimal number. Append ".0" if result has no
781  // decimal/fractional part in order to match output of original codegen.
782  if (result.find('.') == std::string::npos) {
783  result += ".0";
784  }
785 
786  return result;
787 }
788 
789 std::string FloatToString(float value) {
790  std::string result = SimpleFtoa(value);
791  return PostProcessFloat(result);
792 }
793 
794 std::string DoubleToString(double value) {
795  std::string result = SimpleDtoa(value);
796  return PostProcessFloat(result);
797 }
798 
799 // Return true if this is an integral field that should be represented as string
800 // in JS.
801 bool IsIntegralFieldWithStringJSType(const FieldDescriptor* field) {
802  switch (field->cpp_type()) {
805  // The default value of JSType is JS_NORMAL, which behaves the same as
806  // JS_NUMBER.
807  return field->options().jstype() == FieldOptions::JS_STRING;
808  default:
809  return false;
810  }
811 }
812 
813 std::string MaybeNumberString(const FieldDescriptor* field,
814  const std::string& orig) {
815  return IsIntegralFieldWithStringJSType(field) ? ("\"" + orig + "\"") : orig;
816 }
817 
818 std::string JSFieldDefault(const FieldDescriptor* field) {
819  if (field->is_repeated()) {
820  return "[]";
821  }
822 
823  switch (field->cpp_type()) {
825  return MaybeNumberString(field,
826  StrCat(field->default_value_int32()));
828  // The original codegen is in Java, and Java protobufs store unsigned
829  // integer values as signed integer values. In order to exactly match the
830  // output, we need to reinterpret as base-2 signed. Ugh.
831  return MaybeNumberString(
832  field,
833  StrCat(static_cast<int32>(field->default_value_uint32())));
835  return MaybeNumberString(field,
836  StrCat(field->default_value_int64()));
838  // See above note for uint32 -- reinterpreting as signed.
839  return MaybeNumberString(
840  field,
841  StrCat(static_cast<int64>(field->default_value_uint64())));
843  return StrCat(field->default_value_enum()->number());
845  return field->default_value_bool() ? "true" : "false";
847  return FloatToString(field->default_value_float());
849  return DoubleToString(field->default_value_double());
851  if (field->type() == FieldDescriptor::TYPE_STRING) {
852  std::string out;
853  bool is_valid = EscapeJSString(field->default_value_string(), &out);
854  if (!is_valid) {
855  // TODO(b/115551870): Decide whether this should be a hard error.
856  GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name()
857  << " was truncated since it contained invalid UTF-8 or"
858  " codepoints outside the basic multilingual plane.";
859  }
860  return "\"" + out + "\"";
861  } else { // Bytes
862  return "\"" + EscapeBase64(field->default_value_string()) + "\"";
863  }
865  return "null";
866  }
867  GOOGLE_LOG(FATAL) << "Shouldn't reach here.";
868  return "";
869 }
870 
871 std::string ProtoTypeName(const GeneratorOptions& options,
872  const FieldDescriptor* field) {
873  switch (field->type()) {
875  return "bool";
877  return "int32";
879  return "uint32";
881  return "sint32";
883  return "fixed32";
885  return "sfixed32";
887  return "int64";
889  return "uint64";
891  return "sint64";
893  return "fixed64";
895  return "sfixed64";
897  return "float";
899  return "double";
901  return "string";
903  return "bytes";
905  return GetMessagePath(options, field->message_type());
907  return GetEnumPath(options, field->enum_type());
909  return GetMessagePath(options, field->message_type());
910  default:
911  return "";
912  }
913 }
914 
915 std::string JSIntegerTypeName(const FieldDescriptor* field) {
916  return IsIntegralFieldWithStringJSType(field) ? "string" : "number";
917 }
918 
919 std::string JSStringTypeName(const GeneratorOptions& options,
920  const FieldDescriptor* field,
921  BytesMode bytes_mode) {
922  if (field->type() == FieldDescriptor::TYPE_BYTES) {
923  switch (bytes_mode) {
924  case BYTES_DEFAULT:
925  return "(string|Uint8Array)";
926  case BYTES_B64:
927  return "string";
928  case BYTES_U8:
929  return "Uint8Array";
930  default:
931  assert(false);
932  }
933  }
934  return "string";
935 }
936 
937 std::string JSTypeName(const GeneratorOptions& options,
938  const FieldDescriptor* field, BytesMode bytes_mode) {
939  switch (field->cpp_type()) {
941  return "boolean";
943  return JSIntegerTypeName(field);
945  return JSIntegerTypeName(field);
947  return JSIntegerTypeName(field);
949  return JSIntegerTypeName(field);
951  return "number";
953  return "number";
955  return JSStringTypeName(options, field, bytes_mode);
957  return GetEnumPath(options, field->enum_type());
959  return GetMessagePath(options, field->message_type());
960  default:
961  return "";
962  }
963 }
964 
965 // Used inside Google only -- do not remove.
966 bool UseBrokenPresenceSemantics(const GeneratorOptions& options,
967  const FieldDescriptor* field) {
968  return false;
969 }
970 
971 // Returns true for fields that return "null" from accessors when they are
972 // unset. This should normally only be true for non-repeated submessages, but we
973 // have legacy users who relied on old behavior where accessors behaved this
974 // way.
975 bool ReturnsNullWhenUnset(const GeneratorOptions& options,
976  const FieldDescriptor* field) {
977  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
978  field->is_optional()) {
979  return true;
980  }
981 
982  // TODO(haberman): remove this case and unconditionally return false.
983  return UseBrokenPresenceSemantics(options, field) && !field->is_repeated() &&
984  !field->has_default_value();
985 }
986 
987 // In a sane world, this would be the same as ReturnsNullWhenUnset(). But in
988 // the status quo, some fields declare that they never return null/undefined
989 // even though they actually do:
990 // * required fields
991 // * optional enum fields
992 // * proto3 primitive fields.
993 bool DeclaredReturnTypeIsNullable(const GeneratorOptions& options,
994  const FieldDescriptor* field) {
995  if (field->is_required() || field->type() == FieldDescriptor::TYPE_ENUM) {
996  return false;
997  }
998 
999  if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
1000  field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
1001  return false;
1002  }
1003 
1004  return ReturnsNullWhenUnset(options, field);
1005 }
1006 
1007 bool SetterAcceptsUndefined(const GeneratorOptions& options,
1008  const FieldDescriptor* field) {
1009  if (ReturnsNullWhenUnset(options, field)) {
1010  return true;
1011  }
1012 
1013  // Broken presence semantics always accepts undefined for setters.
1014  return UseBrokenPresenceSemantics(options, field);
1015 }
1016 
1017 bool SetterAcceptsNull(const GeneratorOptions& options,
1018  const FieldDescriptor* field) {
1019  if (ReturnsNullWhenUnset(options, field)) {
1020  return true;
1021  }
1022 
1023  // With broken presence semantics, fields with defaults accept "null" for
1024  // setters, but other fields do not. This is a strange quirk of the old
1025  // codegen.
1026  return UseBrokenPresenceSemantics(options, field) &&
1027  field->has_default_value();
1028 }
1029 
1030 // Returns types which are known to by non-nullable by default.
1031 // The style guide requires that we omit "!" in this case.
1032 bool IsPrimitive(const std::string& type) {
1033  return type == "undefined" || type == "string" || type == "number" ||
1034  type == "boolean";
1035 }
1036 
1037 std::string JSFieldTypeAnnotation(const GeneratorOptions& options,
1038  const FieldDescriptor* field,
1039  bool is_setter_argument, bool force_present,
1040  bool singular_if_not_packed,
1041  BytesMode bytes_mode = BYTES_DEFAULT,
1042  bool force_singular = false) {
1043  std::string jstype = JSTypeName(options, field, bytes_mode);
1044 
1045  if (!force_singular && field->is_repeated() &&
1046  (field->is_packed() || !singular_if_not_packed)) {
1047  if (field->type() == FieldDescriptor::TYPE_BYTES &&
1048  bytes_mode == BYTES_DEFAULT) {
1049  jstype = "(Array<!Uint8Array>|Array<string>)";
1050  } else {
1051  if (!IsPrimitive(jstype)) {
1052  jstype = "!" + jstype;
1053  }
1054  jstype = "Array<" + jstype + ">";
1055  }
1056  }
1057 
1058  bool is_null_or_undefined = false;
1059 
1060  if (is_setter_argument) {
1061  if (SetterAcceptsNull(options, field)) {
1062  jstype = "?" + jstype;
1063  is_null_or_undefined = true;
1064  }
1065 
1066  if (SetterAcceptsUndefined(options, field)) {
1067  jstype += "|undefined";
1068  is_null_or_undefined = true;
1069  }
1070  } else if (force_present) {
1071  // Don't add null or undefined.
1072  } else {
1073  if (DeclaredReturnTypeIsNullable(options, field)) {
1074  jstype = "?" + jstype;
1075  is_null_or_undefined = true;
1076  }
1077  }
1078 
1079  if (!is_null_or_undefined && !IsPrimitive(jstype)) {
1080  jstype = "!" + jstype;
1081  }
1082 
1083  return jstype;
1084 }
1085 
1086 std::string JSBinaryReaderMethodType(const FieldDescriptor* field) {
1087  std::string name = field->type_name();
1088  if (name[0] >= 'a' && name[0] <= 'z') {
1089  name[0] = (name[0] - 'a') + 'A';
1090  }
1091  return IsIntegralFieldWithStringJSType(field) ? (name + "String") : name;
1092 }
1093 
1094 std::string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
1095  bool is_writer) {
1096  std::string name = JSBinaryReaderMethodType(field);
1097  if (field->is_packed()) {
1098  name = "Packed" + name;
1099  } else if (is_writer && field->is_repeated()) {
1100  name = "Repeated" + name;
1101  }
1102  return name;
1103 }
1104 
1105 std::string JSBinaryReaderMethodName(const GeneratorOptions& options,
1106  const FieldDescriptor* field) {
1107  return "jspb.BinaryReader.prototype.read" +
1108  JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
1109 }
1110 
1111 std::string JSBinaryWriterMethodName(const GeneratorOptions& options,
1112  const FieldDescriptor* field) {
1113  if (field->containing_type() &&
1114  field->containing_type()->options().message_set_wire_format()) {
1115  return "jspb.BinaryWriter.prototype.writeMessageSet";
1116  }
1117  return "jspb.BinaryWriter.prototype.write" +
1118  JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
1119 }
1120 
1121 std::string JSReturnClause(const FieldDescriptor* desc) {
1122  return "";
1123 }
1124 
1125 std::string JSTypeTag(const FieldDescriptor* desc) {
1126  switch (desc->type()) {
1129  return "Float";
1140  if (IsIntegralFieldWithStringJSType(desc)) {
1141  return "StringInt";
1142  } else {
1143  return "Int";
1144  }
1146  return "Boolean";
1148  return "String";
1150  return "Bytes";
1152  return "Enum";
1153  default:
1154  assert(false);
1155  }
1156  return "";
1157 }
1158 
1159 std::string JSReturnDoc(const GeneratorOptions& options,
1160  const FieldDescriptor* desc) {
1161  return "";
1162 }
1163 
1165  const Descriptor* desc) {
1166  for (int i = 0; i < desc->field_count(); i++) {
1167  if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
1168  return true;
1169  }
1170  }
1171  return false;
1172 }
1173 
1174 static const char* kRepeatedFieldArrayName = ".repeatedFields_";
1175 
1176 std::string RepeatedFieldsArrayName(const GeneratorOptions& options,
1177  const Descriptor* desc) {
1178  return HasRepeatedFields(options, desc)
1179  ? (GetMessagePath(options, desc) + kRepeatedFieldArrayName)
1180  : "null";
1181 }
1182 
1183 bool HasOneofFields(const Descriptor* desc) {
1184  for (int i = 0; i < desc->field_count(); i++) {
1185  if (desc->field(i)->containing_oneof()) {
1186  return true;
1187  }
1188  }
1189  return false;
1190 }
1191 
1192 static const char* kOneofGroupArrayName = ".oneofGroups_";
1193 
1194 std::string OneofFieldsArrayName(const GeneratorOptions& options,
1195  const Descriptor* desc) {
1196  return HasOneofFields(desc)
1197  ? (GetMessagePath(options, desc) + kOneofGroupArrayName)
1198  : "null";
1199 }
1200 
1201 std::string RepeatedFieldNumberList(const GeneratorOptions& options,
1202  const Descriptor* desc) {
1203  std::vector<std::string> numbers;
1204  for (int i = 0; i < desc->field_count(); i++) {
1205  if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
1206  numbers.push_back(JSFieldIndex(desc->field(i)));
1207  }
1208  }
1209  return "[" + Join(numbers, ",") + "]";
1210 }
1211 
1212 std::string OneofGroupList(const Descriptor* desc) {
1213  // List of arrays (one per oneof), each of which is a list of field indices
1214  std::vector<std::string> oneof_entries;
1215  for (int i = 0; i < desc->oneof_decl_count(); i++) {
1216  const OneofDescriptor* oneof = desc->oneof_decl(i);
1217  if (IgnoreOneof(oneof)) {
1218  continue;
1219  }
1220 
1221  std::vector<std::string> oneof_fields;
1222  for (int j = 0; j < oneof->field_count(); j++) {
1223  if (IgnoreField(oneof->field(j))) {
1224  continue;
1225  }
1226  oneof_fields.push_back(JSFieldIndex(oneof->field(j)));
1227  }
1228  oneof_entries.push_back("[" + Join(oneof_fields, ",") + "]");
1229  }
1230  return "[" + Join(oneof_entries, ",") + "]";
1231 }
1232 
1233 std::string JSOneofArray(const GeneratorOptions& options,
1234  const FieldDescriptor* field) {
1235  return OneofFieldsArrayName(options, field->containing_type()) + "[" +
1236  JSOneofIndex(field->containing_oneof()) + "]";
1237 }
1238 
1239 std::string RelativeTypeName(const FieldDescriptor* field) {
1240  assert(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM ||
1241  field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
1242  // For a field with an enum or message type, compute a name relative to the
1243  // path name of the message type containing this field.
1244  std::string package = field->file()->package();
1245  std::string containing_type = field->containing_type()->full_name() + ".";
1247  ? field->enum_type()->full_name()
1248  : field->message_type()->full_name();
1249 
1250  // |prefix| is advanced as we find separators '.' past the common package
1251  // prefix that yield common prefixes in the containing type's name and this
1252  // type's name.
1253  int prefix = 0;
1254  for (int i = 0; i < type.size() && i < containing_type.size(); i++) {
1255  if (type[i] != containing_type[i]) {
1256  break;
1257  }
1258  if (type[i] == '.' && i >= package.size()) {
1259  prefix = i + 1;
1260  }
1261  }
1262 
1263  return type.substr(prefix);
1264 }
1265 
1266 std::string JSExtensionsObjectName(const GeneratorOptions& options,
1267  const FileDescriptor* from_file,
1268  const Descriptor* desc) {
1269  if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
1270  // TODO(haberman): fix this for the kImportCommonJs case.
1271  return "jspb.Message.messageSetExtensions";
1272  } else {
1273  return MaybeCrossFileRef(options, from_file, desc) + ".extensions";
1274  }
1275 }
1276 
1277 static const int kMapKeyField = 1;
1278 static const int kMapValueField = 2;
1279 
1280 const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) {
1281  assert(field->is_map());
1282  return field->message_type()->FindFieldByNumber(kMapKeyField);
1283 }
1284 
1285 const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) {
1286  assert(field->is_map());
1287  return field->message_type()->FindFieldByNumber(kMapValueField);
1288 }
1289 
1290 std::string FieldDefinition(const GeneratorOptions& options,
1291  const FieldDescriptor* field) {
1292  if (field->is_map()) {
1293  const FieldDescriptor* key_field = MapFieldKey(field);
1294  const FieldDescriptor* value_field = MapFieldValue(field);
1295  std::string key_type = ProtoTypeName(options, key_field);
1297  if (value_field->type() == FieldDescriptor::TYPE_ENUM ||
1298  value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
1299  value_type = RelativeTypeName(value_field);
1300  } else {
1301  value_type = ProtoTypeName(options, value_field);
1302  }
1303  return StringPrintf("map<%s, %s> %s = %d;", key_type.c_str(),
1304  value_type.c_str(), field->name().c_str(),
1305  field->number());
1306  } else {
1307  std::string qualifier =
1308  field->is_repeated() ? "repeated"
1309  : (field->is_optional() ? "optional" : "required");
1311  if (field->type() == FieldDescriptor::TYPE_ENUM ||
1312  field->type() == FieldDescriptor::TYPE_MESSAGE) {
1313  type = RelativeTypeName(field);
1314  name = field->name();
1315  } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
1316  type = "group";
1317  name = field->message_type()->name();
1318  } else {
1319  type = ProtoTypeName(options, field);
1320  name = field->name();
1321  }
1322  return StringPrintf("%s %s %s = %d;", qualifier.c_str(), type.c_str(),
1323  name.c_str(), field->number());
1324  }
1325 }
1326 
1327 std::string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
1328  std::string comments;
1329  if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) {
1330  comments +=
1331  " * Note that Uint8Array is not supported on all browsers.\n"
1332  " * @see http://caniuse.com/Uint8Array\n";
1333  }
1334  return comments;
1335 }
1336 
1337 bool ShouldGenerateExtension(const FieldDescriptor* field) {
1338  return field->is_extension() && !IgnoreField(field);
1339 }
1340 
1341 bool HasExtensions(const Descriptor* desc) {
1342  for (int i = 0; i < desc->extension_count(); i++) {
1343  if (ShouldGenerateExtension(desc->extension(i))) {
1344  return true;
1345  }
1346  }
1347  for (int i = 0; i < desc->nested_type_count(); i++) {
1348  if (HasExtensions(desc->nested_type(i))) {
1349  return true;
1350  }
1351  }
1352  return false;
1353 }
1354 
1355 bool HasExtensions(const FileDescriptor* file) {
1356  for (int i = 0; i < file->extension_count(); i++) {
1357  if (ShouldGenerateExtension(file->extension(i))) {
1358  return true;
1359  }
1360  }
1361  for (int i = 0; i < file->message_type_count(); i++) {
1362  if (HasExtensions(file->message_type(i))) {
1363  return true;
1364  }
1365  }
1366  return false;
1367 }
1368 
1369 bool HasMap(const GeneratorOptions& options, const Descriptor* desc) {
1370  for (int i = 0; i < desc->field_count(); i++) {
1371  if (desc->field(i)->is_map()) {
1372  return true;
1373  }
1374  }
1375  for (int i = 0; i < desc->nested_type_count(); i++) {
1376  if (HasMap(options, desc->nested_type(i))) {
1377  return true;
1378  }
1379  }
1380  return false;
1381 }
1382 
1383 bool FileHasMap(const GeneratorOptions& options, const FileDescriptor* desc) {
1384  for (int i = 0; i < desc->message_type_count(); i++) {
1385  if (HasMap(options, desc->message_type(i))) {
1386  return true;
1387  }
1388  }
1389  return false;
1390 }
1391 
1392 bool IsExtendable(const Descriptor* desc) {
1393  return desc->extension_range_count() > 0;
1394 }
1395 
1396 // Returns the max index in the underlying data storage array beyond which the
1397 // extension object is used.
1398 std::string GetPivot(const Descriptor* desc) {
1399  static const int kDefaultPivot = 500;
1400 
1401  // Find the max field number
1402  int max_field_number = 0;
1403  for (int i = 0; i < desc->field_count(); i++) {
1404  if (!IgnoreField(desc->field(i)) &&
1405  desc->field(i)->number() > max_field_number) {
1406  max_field_number = desc->field(i)->number();
1407  }
1408  }
1409 
1410  int pivot = -1;
1411  if (IsExtendable(desc) || (max_field_number >= kDefaultPivot)) {
1412  pivot = ((max_field_number + 1) < kDefaultPivot) ? (max_field_number + 1)
1413  : kDefaultPivot;
1414  }
1415 
1416  return StrCat(pivot);
1417 }
1418 
1419 // Whether this field represents presence. For fields with presence, we
1420 // generate extra methods (clearFoo() and hasFoo()) for this field.
1422  const FieldDescriptor* field) {
1423  if (field->is_repeated() || field->is_map()) {
1424  // We say repeated fields and maps don't have presence, but we still do
1425  // generate clearFoo() methods for them through a special case elsewhere.
1426  return false;
1427  }
1428 
1429  if (UseBrokenPresenceSemantics(options, field)) {
1430  // Proto3 files with broken presence semantics have field presence.
1431  return true;
1432  }
1433 
1434  return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
1435  field->containing_oneof() != NULL ||
1436  field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2;
1437 }
1438 
1439 // We use this to implement the semantics that same file can be generated
1440 // multiple times, but only the last one keep the short name. Others all use
1441 // long name with extra information to distinguish (For message and enum, the
1442 // extra information is package name, for file level extension, the extra
1443 // information is proto's filename).
1444 // We never actually write the files, but we keep a set of which descriptors
1445 // were the final one for a given filename.
1446 class FileDeduplicator {
1447  public:
1448  explicit FileDeduplicator(const GeneratorOptions& options)
1449  : error_on_conflict_(options.error_on_name_conflict) {}
1450 
1451  // params:
1452  // filenames: a pair of {short filename, full filename}
1453  // (short filename don't have extra information, full filename
1454  // contains extra information)
1455  // desc: The Descriptor or SCC pointer or EnumDescriptor.
1456  // error: The returned error information.
1457  bool AddFile(const std::pair<std::string, std::string> filenames,
1458  const void* desc, std::string* error) {
1459  if (descs_by_shortname_.find(filenames.first) !=
1460  descs_by_shortname_.end()) {
1461  if (error_on_conflict_) {
1462  *error = "Name conflict: file name " + filenames.first +
1463  " would be generated by two descriptors";
1464  return false;
1465  }
1466  // Change old pointer's actual name to full name.
1467  auto short_name_desc = descs_by_shortname_[filenames.first];
1468  allowed_descs_actual_name_[short_name_desc] =
1469  allowed_descs_full_name_[short_name_desc];
1470  }
1471  descs_by_shortname_[filenames.first] = desc;
1472  allowed_descs_actual_name_[desc] = filenames.first;
1473  allowed_descs_full_name_[desc] = filenames.second;
1474 
1475  return true;
1476  }
1477 
1478  void GetAllowedMap(std::map<const void*, std::string>* allowed_set) {
1479  *allowed_set = allowed_descs_actual_name_;
1480  }
1481 
1482  private:
1484  // The map that restores all the descs that are using short name as filename.
1485  std::map<std::string, const void*> descs_by_shortname_;
1486  // The final actual filename map.
1487  std::map<const void*, std::string> allowed_descs_actual_name_;
1488  // The full name map.
1489  std::map<const void*, std::string> allowed_descs_full_name_;
1490 };
1491 
1492 void DepthFirstSearch(const FileDescriptor* file,
1493  std::vector<const FileDescriptor*>* list,
1494  std::set<const FileDescriptor*>* seen) {
1495  if (!seen->insert(file).second) {
1496  return;
1497  }
1498 
1499  // Add all dependencies.
1500  for (int i = 0; i < file->dependency_count(); i++) {
1501  DepthFirstSearch(file->dependency(i), list, seen);
1502  }
1503 
1504  // Add this file.
1505  list->push_back(file);
1506 }
1507 
1508 // A functor for the predicate to remove_if() below. Returns true if a given
1509 // FileDescriptor is not in the given set.
1510 class NotInSet {
1511  public:
1512  explicit NotInSet(const std::set<const FileDescriptor*>& file_set)
1513  : file_set_(file_set) {}
1514 
1515  bool operator()(const FileDescriptor* file) {
1516  return file_set_.count(file) == 0;
1517  }
1518 
1519  private:
1520  const std::set<const FileDescriptor*>& file_set_;
1521 };
1522 
1523 // This function generates an ordering of the input FileDescriptors that matches
1524 // the logic of the old code generator. The order is significant because two
1525 // different input files can generate the same output file, and the last one
1526 // needs to win.
1527 void GenerateJspbFileOrder(const std::vector<const FileDescriptor*>& input,
1528  std::vector<const FileDescriptor*>* ordered) {
1529  // First generate an ordering of all reachable files (including dependencies)
1530  // with depth-first search. This mimics the behavior of --include_imports,
1531  // which is what the old codegen used.
1532  ordered->clear();
1533  std::set<const FileDescriptor*> seen;
1534  std::set<const FileDescriptor*> input_set;
1535  for (int i = 0; i < input.size(); i++) {
1536  DepthFirstSearch(input[i], ordered, &seen);
1537  input_set.insert(input[i]);
1538  }
1539 
1540  // Now remove the entries that are not actually in our input list.
1541  ordered->erase(
1542  std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)),
1543  ordered->end());
1544 }
1545 
1546 // If we're generating code in file-per-type mode, avoid overwriting files
1547 // by choosing the last descriptor that writes each filename and permitting
1548 // only those to generate code.
1549 
1550 struct DepsGenerator {
1551  std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
1552  std::vector<const Descriptor*> deps;
1553  auto maybe_add = [&](const Descriptor* d) {
1554  if (d) deps.push_back(d);
1555  };
1556  for (int i = 0; i < desc->field_count(); i++) {
1557  if (!IgnoreField(desc->field(i))) {
1558  maybe_add(desc->field(i)->message_type());
1559  }
1560  }
1561  for (int i = 0; i < desc->extension_count(); i++) {
1562  maybe_add(desc->extension(i)->message_type());
1563  maybe_add(desc->extension(i)->containing_type());
1564  }
1565  for (int i = 0; i < desc->nested_type_count(); i++) {
1566  maybe_add(desc->nested_type(i));
1567  }
1568  maybe_add(desc->containing_type());
1569 
1570  return deps;
1571  }
1572 };
1573 
1574 bool GenerateJspbAllowedMap(const GeneratorOptions& options,
1575  const std::vector<const FileDescriptor*>& files,
1576  std::map<const void*, std::string>* allowed_set,
1577  SCCAnalyzer<DepsGenerator>* analyzer,
1578  std::string* error) {
1579  std::vector<const FileDescriptor*> files_ordered;
1580  GenerateJspbFileOrder(files, &files_ordered);
1581 
1582  // Choose the last descriptor for each filename.
1583  FileDeduplicator dedup(options);
1584  std::set<const SCC*> added;
1585  for (int i = 0; i < files_ordered.size(); i++) {
1586  for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
1587  const Descriptor* desc = files_ordered[i]->message_type(j);
1588  if (added.insert(analyzer->GetSCC(desc)).second &&
1589  !dedup.AddFile(
1590  std::make_pair(
1591  GetMessagesFileName(options, analyzer->GetSCC(desc), false),
1592  GetMessagesFileName(options, analyzer->GetSCC(desc), true)),
1593  analyzer->GetSCC(desc), error)) {
1594  return false;
1595  }
1596  }
1597  for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
1598  const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
1599  if (!dedup.AddFile(std::make_pair(GetEnumFileName(options, desc, false),
1600  GetEnumFileName(options, desc, true)),
1601  desc, error)) {
1602  return false;
1603  }
1604  }
1605 
1606  // Pull out all free-floating extensions and generate files for those too.
1607  bool has_extension = false;
1608 
1609  for (int j = 0; j < files_ordered[i]->extension_count(); j++) {
1610  if (ShouldGenerateExtension(files_ordered[i]->extension(j))) {
1611  has_extension = true;
1612  }
1613  }
1614 
1615  if (has_extension) {
1616  if (!dedup.AddFile(
1617  std::make_pair(
1618  GetExtensionFileName(options, files_ordered[i], false),
1619  GetExtensionFileName(options, files_ordered[i], true)),
1620  files_ordered[i], error)) {
1621  return false;
1622  }
1623  }
1624  }
1625 
1626  dedup.GetAllowedMap(allowed_set);
1627 
1628  return true;
1629 }
1630 
1631 // Embeds base64 encoded GeneratedCodeInfo proto in a comment at the end of
1632 // file.
1633 void EmbedCodeAnnotations(const GeneratedCodeInfo& annotations,
1634  io::Printer* printer) {
1635  // Serialize annotations proto into base64 string.
1636  std::string meta_content;
1637  annotations.SerializeToString(&meta_content);
1638  std::string meta_64;
1639  Base64Escape(meta_content, &meta_64);
1640 
1641  // Print base64 encoded annotations at the end of output file in
1642  // a comment.
1643  printer->Print("\n// Below is base64 encoded GeneratedCodeInfo proto");
1644  printer->Print("\n// $encoded_proto$\n", "encoded_proto", meta_64);
1645 }
1646 
1647 bool IsWellKnownTypeFile(const FileDescriptor* file) {
1648  return HasPrefixString(file->name(), "google/protobuf/");
1649 }
1650 
1651 } // anonymous namespace
1652 
1654  const FileDescriptor* file,
1655  io::Printer* printer) const {
1656  if (file != nullptr) {
1657  printer->Print("// source: $filename$\n", "filename", file->name());
1658  }
1659  printer->Print(
1660  "/**\n"
1661  " * @fileoverview\n"
1662  " * @enhanceable\n"
1663  " * @suppress {messageConventions} JS Compiler reports an "
1664  "error if a variable or\n"
1665  " * field starts with 'MSG_' and isn't a translatable "
1666  "message.\n"
1667  " * @public\n"
1668  " */\n"
1669  "// GENERATED CODE -- DO NOT EDIT!\n"
1670  "\n");
1671 }
1672 
1674  io::Printer* printer,
1675  const FileDescriptor* file,
1676  std::set<std::string>* provided) const {
1677  for (int i = 0; i < file->message_type_count(); i++) {
1678  FindProvidesForMessage(options, printer, file->message_type(i), provided);
1679  }
1680  for (int i = 0; i < file->enum_type_count(); i++) {
1681  FindProvidesForEnum(options, printer, file->enum_type(i), provided);
1682  }
1683 }
1684 
1686  io::Printer* printer,
1687  const std::vector<const FileDescriptor*>& files,
1688  std::set<std::string>* provided) const {
1689  for (int i = 0; i < files.size(); i++) {
1690  FindProvidesForFile(options, printer, files[i], provided);
1691  }
1692 
1693  printer->Print("\n");
1694 }
1695 
1697  const OneofDescriptor* oneof,
1698  std::set<std::string>* provided) {
1699  std::string name = GetMessagePath(options, oneof->containing_type()) + "." +
1700  JSOneofName(oneof) + "Case";
1701  provided->insert(name);
1702 }
1703 
1705  io::Printer* printer, const Descriptor* desc,
1706  std::set<std::string>* provided) {
1707  if (HasOneofFields(desc)) {
1708  for (int i = 0; i < desc->oneof_decl_count(); i++) {
1709  if (IgnoreOneof(desc->oneof_decl(i))) {
1710  continue;
1711  }
1712  FindProvidesForOneOfEnum(options, desc->oneof_decl(i), provided);
1713  }
1714  }
1715 }
1716 
1718  io::Printer* printer,
1719  const Descriptor* desc,
1720  std::set<std::string>* provided) const {
1721  if (IgnoreMessage(desc)) {
1722  return;
1723  }
1724 
1725  std::string name = GetMessagePath(options, desc);
1726  provided->insert(name);
1727 
1728  for (int i = 0; i < desc->enum_type_count(); i++) {
1729  FindProvidesForEnum(options, printer, desc->enum_type(i), provided);
1730  }
1731 
1732  FindProvidesForOneOfEnums(options, printer, desc, provided);
1733 
1734  for (int i = 0; i < desc->nested_type_count(); i++) {
1735  FindProvidesForMessage(options, printer, desc->nested_type(i), provided);
1736  }
1737 }
1739  io::Printer* printer,
1740  const EnumDescriptor* enumdesc,
1741  std::set<std::string>* provided) const {
1742  std::string name = GetEnumPath(options, enumdesc);
1743  provided->insert(name);
1744 }
1745 
1747  const GeneratorOptions& options, io::Printer* printer,
1748  const std::vector<const FieldDescriptor*>& fields,
1749  std::set<std::string>* provided) const {
1750  for (int i = 0; i < fields.size(); i++) {
1751  const FieldDescriptor* field = fields[i];
1752 
1753  if (IgnoreField(field)) {
1754  continue;
1755  }
1756 
1757  std::string name = GetNamespace(options, field->file()) + "." +
1758  JSObjectFieldName(options, field);
1759  provided->insert(name);
1760  }
1761 }
1762 
1764  io::Printer* printer,
1765  std::set<std::string>* provided) const {
1766  for (std::set<std::string>::iterator it = provided->begin();
1767  it != provided->end(); ++it) {
1768  if (options.import_style == GeneratorOptions::kImportClosure) {
1769  printer->Print("goog.provide('$name$');\n", "name", *it);
1770  } else {
1771  // We aren't using Closure's import system, but we use goog.exportSymbol()
1772  // to construct the expected tree of objects, eg.
1773  //
1774  // goog.exportSymbol('foo.bar.Baz', null, this);
1775  //
1776  // // Later generated code expects foo.bar = {} to exist:
1777  // foo.bar.Baz = function() { /* ... */ }
1778 
1779  // Do not use global scope in strict mode
1780  if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
1781  std::string namespaceObject = *it;
1782  // Remove "proto." from the namespace object
1783  GOOGLE_CHECK_EQ(0, namespaceObject.compare(0, 6, "proto."));
1784  namespaceObject.erase(0, 6);
1785  printer->Print("goog.exportSymbol('$name$', null, proto);\n", "name",
1786  namespaceObject);
1787  } else {
1788  printer->Print("goog.exportSymbol('$name$', null, global);\n", "name",
1789  *it);
1790  }
1791  }
1792  }
1793 }
1794 
1796  io::Printer* printer, const SCC* scc,
1797  std::set<std::string>* provided) const {
1798  std::set<std::string> required;
1799  std::set<std::string> forwards;
1800  bool have_message = false;
1801  bool has_extension = false;
1802  bool has_map = false;
1803  for (auto desc : scc->descriptors) {
1804  if (desc->containing_type() == nullptr) {
1805  FindRequiresForMessage(options, desc, &required, &forwards,
1806  &have_message);
1807  has_extension = (has_extension || HasExtensions(desc));
1808  has_map = (has_map || HasMap(options, desc));
1809  }
1810  }
1811 
1812  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
1813  /* require_jspb = */ have_message,
1814  /* require_extension = */ has_extension,
1815  /* require_map = */ has_map);
1816 }
1817 
1819  const GeneratorOptions& options, io::Printer* printer,
1820  const std::vector<const FileDescriptor*>& files,
1821  std::set<std::string>* provided) const {
1823  // For Closure imports we need to import every message type individually.
1824  std::set<std::string> required;
1825  std::set<std::string> forwards;
1826  bool have_extensions = false;
1827  bool have_map = false;
1828  bool have_message = false;
1829 
1830  for (int i = 0; i < files.size(); i++) {
1831  for (int j = 0; j < files[i]->message_type_count(); j++) {
1832  const Descriptor* desc = files[i]->message_type(j);
1833  if (!IgnoreMessage(desc)) {
1834  FindRequiresForMessage(options, desc, &required, &forwards,
1835  &have_message);
1836  }
1837  }
1838 
1839  if (!have_extensions && HasExtensions(files[i])) {
1840  have_extensions = true;
1841  }
1842 
1843  if (!have_map && FileHasMap(options, files[i])) {
1844  have_map = true;
1845  }
1846 
1847  for (int j = 0; j < files[i]->extension_count(); j++) {
1848  const FieldDescriptor* extension = files[i]->extension(j);
1849  if (IgnoreField(extension)) {
1850  continue;
1851  }
1852  if (extension->containing_type()->full_name() !=
1853  "google.protobuf.bridge.MessageSet") {
1854  required.insert(GetMessagePath(options, extension->containing_type()));
1855  }
1856  FindRequiresForField(options, extension, &required, &forwards);
1857  have_extensions = true;
1858  }
1859  }
1860 
1861  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
1862  /* require_jspb = */ have_message,
1863  /* require_extension = */ have_extensions,
1864  /* require_map = */ have_map);
1865 }
1866 
1868  const GeneratorOptions& options, io::Printer* printer,
1869  const std::vector<const FieldDescriptor*>& fields,
1870  std::set<std::string>* provided) const {
1871  std::set<std::string> required;
1872  std::set<std::string> forwards;
1873  for (int i = 0; i < fields.size(); i++) {
1874  const FieldDescriptor* field = fields[i];
1875  if (IgnoreField(field)) {
1876  continue;
1877  }
1878  FindRequiresForExtension(options, field, &required, &forwards);
1879  }
1880 
1881  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
1882  /* require_jspb = */ false,
1883  /* require_extension = */ fields.size() > 0,
1884  /* require_map = */ false);
1885 }
1886 
1888  io::Printer* printer,
1889  std::set<std::string>* required,
1890  std::set<std::string>* forwards,
1891  std::set<std::string>* provided,
1892  bool require_jspb, bool require_extension,
1893  bool require_map) const {
1894  if (require_jspb) {
1895  required->insert("jspb.Message");
1896  required->insert("jspb.BinaryReader");
1897  required->insert("jspb.BinaryWriter");
1898  }
1899  if (require_extension) {
1900  required->insert("jspb.ExtensionFieldBinaryInfo");
1901  required->insert("jspb.ExtensionFieldInfo");
1902  }
1903  if (require_map) {
1904  required->insert("jspb.Map");
1905  }
1906 
1907  std::set<std::string>::iterator it;
1908  for (it = required->begin(); it != required->end(); ++it) {
1909  if (provided->find(*it) != provided->end()) {
1910  continue;
1911  }
1912  printer->Print("goog.require('$name$');\n", "name", *it);
1913  }
1914 
1915  printer->Print("\n");
1916 
1917  for (it = forwards->begin(); it != forwards->end(); ++it) {
1918  if (provided->find(*it) != provided->end()) {
1919  continue;
1920  }
1921  printer->Print("goog.forwardDeclare('$name$');\n", "name", *it);
1922  }
1923 }
1924 
1926  return false;
1927 }
1928 
1930  const Descriptor* desc,
1931  std::set<std::string>* required,
1932  std::set<std::string>* forwards,
1933  bool* have_message) const {
1934 
1935  if (!NamespaceOnly(desc)) {
1936  *have_message = true;
1937  for (int i = 0; i < desc->field_count(); i++) {
1938  const FieldDescriptor* field = desc->field(i);
1939  if (IgnoreField(field)) {
1940  continue;
1941  }
1942  FindRequiresForField(options, field, required, forwards);
1943  }
1944  }
1945 
1946  for (int i = 0; i < desc->extension_count(); i++) {
1947  const FieldDescriptor* field = desc->extension(i);
1948  if (IgnoreField(field)) {
1949  continue;
1950  }
1951  FindRequiresForExtension(options, field, required, forwards);
1952  }
1953 
1954  for (int i = 0; i < desc->nested_type_count(); i++) {
1955  FindRequiresForMessage(options, desc->nested_type(i), required, forwards,
1956  have_message);
1957  }
1958 }
1959 
1961  const FieldDescriptor* field,
1962  std::set<std::string>* required,
1963  std::set<std::string>* forwards) const {
1964  if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
1965  // N.B.: file-level extensions with enum type do *not* create
1966  // dependencies, as per original codegen.
1967  !(field->is_extension() && field->extension_scope() == nullptr)) {
1968  if (options.add_require_for_enums) {
1969  required->insert(GetEnumPath(options, field->enum_type()));
1970  } else {
1971  forwards->insert(GetEnumPath(options, field->enum_type()));
1972  }
1973  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1974  if (!IgnoreMessage(field->message_type())) {
1975  required->insert(GetMessagePath(options, field->message_type()));
1976  }
1977  }
1978 }
1979 
1982  std::set<std::string>* required, std::set<std::string>* forwards) const {
1983  if (field->containing_type()->full_name() != "google.protobuf.bridge.MessageSet") {
1984  required->insert(GetMessagePath(options, field->containing_type()));
1985  }
1986  FindRequiresForField(options, field, required, forwards);
1987 }
1988 
1990  io::Printer* printer) const {
1991  if (options.testonly) {
1992  printer->Print("goog.setTestOnly();\n\n");
1993  }
1994  printer->Print("\n");
1995 }
1996 
1998  io::Printer* printer,
1999  const FileDescriptor* file) const {
2000  for (int i = 0; i < file->message_type_count(); i++) {
2002  file->message_type(i));
2003  }
2004  for (int i = 0; i < file->message_type_count(); i++) {
2005  GenerateClass(options, printer, file->message_type(i));
2006  }
2007  for (int i = 0; i < file->enum_type_count(); i++) {
2008  GenerateEnum(options, printer, file->enum_type(i));
2009  }
2010 }
2011 
2013  io::Printer* printer,
2014  const Descriptor* desc) const {
2015  if (IgnoreMessage(desc)) {
2016  return;
2017  }
2018 
2019  if (!NamespaceOnly(desc)) {
2020  printer->Print("\n");
2021  GenerateClassFieldInfo(options, printer, desc);
2022 
2023 
2024  GenerateClassToObject(options, printer, desc);
2025  // These must come *before* the extension-field info generation in
2026  // GenerateClassRegistration so that references to the binary
2027  // serialization/deserialization functions may be placed in the extension
2028  // objects.
2031  }
2032 
2033  // Recurse on nested types. These must come *before* the extension-field
2034  // info generation in GenerateClassRegistration so that extensions that
2035  // reference nested types proceed the definitions of the nested types.
2036  for (int i = 0; i < desc->enum_type_count(); i++) {
2037  GenerateEnum(options, printer, desc->enum_type(i));
2038  }
2039  for (int i = 0; i < desc->nested_type_count(); i++) {
2040  GenerateClass(options, printer, desc->nested_type(i));
2041  }
2042 
2043  if (!NamespaceOnly(desc)) {
2045  GenerateClassFields(options, printer, desc);
2046 
2047  if (options.import_style != GeneratorOptions::kImportClosure) {
2048  for (int i = 0; i < desc->extension_count(); i++) {
2049  GenerateExtension(options, printer, desc->extension(i));
2050  }
2051  }
2052  }
2053 }
2054 
2056  io::Printer* printer,
2057  const Descriptor* desc) const {
2058  printer->Print(
2059  "/**\n"
2060  " * Generated by JsPbCodeGenerator.\n"
2061  " * @param {Array=} opt_data Optional initial data array, typically "
2062  "from a\n"
2063  " * server response, or constructed directly in Javascript. The array "
2064  "is used\n"
2065  " * in place and becomes part of the constructed object. It is not "
2066  "cloned.\n"
2067  " * If no data is provided, the constructed object will be empty, but "
2068  "still\n"
2069  " * valid.\n"
2070  " * @extends {jspb.Message}\n"
2071  " * @constructor\n"
2072  " */\n"
2073  "$classprefix$$classname$ = function(opt_data) {\n",
2074  "classprefix", GetMessagePathPrefix(options, desc), "classname",
2075  desc->name());
2076  printer->Annotate("classname", desc);
2077  std::string message_id = GetMessageId(desc);
2078  printer->Print(
2079  " jspb.Message.initialize(this, opt_data, $messageId$, $pivot$, "
2080  "$rptfields$, $oneoffields$);\n",
2081  "messageId",
2082  !message_id.empty() ? ("'" + message_id + "'")
2083  : (IsResponse(desc) ? "''" : "0"),
2084  "pivot", GetPivot(desc), "rptfields",
2085  RepeatedFieldsArrayName(options, desc), "oneoffields",
2086  OneofFieldsArrayName(options, desc));
2087  printer->Print(
2088  "};\n"
2089  "goog.inherits($classname$, jspb.Message);\n"
2090  "if (goog.DEBUG && !COMPILED) {\n"
2091  // displayName overrides Function.prototype.displayName
2092  // http://google3/javascript/externs/es3.js?l=511
2093  " /**\n"
2094  " * @public\n"
2095  " * @override\n"
2096  " */\n"
2097  " $classname$.displayName = '$classname$';\n"
2098  "}\n",
2099  "classname", GetMessagePath(options, desc));
2100 }
2101 
2103  const GeneratorOptions& options, io::Printer* printer,
2104  const Descriptor* desc) const {
2105  if (!NamespaceOnly(desc)) {
2107  if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
2109  }
2110  }
2111  for (int i = 0; i < desc->nested_type_count(); i++) {
2112  if (!IgnoreMessage(desc->nested_type(i))) {
2114  options, printer, desc->nested_type(i));
2115  }
2116  }
2117 }
2118 
2120  io::Printer* printer,
2121  const Descriptor* desc) const {
2122  if (HasRepeatedFields(options, desc)) {
2123  printer->Print(
2124  "/**\n"
2125  " * List of repeated fields within this message type.\n"
2126  " * @private {!Array<number>}\n"
2127  " * @const\n"
2128  " */\n"
2129  "$classname$$rptfieldarray$ = $rptfields$;\n"
2130  "\n",
2131  "classname", GetMessagePath(options, desc), "rptfieldarray",
2132  kRepeatedFieldArrayName, "rptfields",
2133  RepeatedFieldNumberList(options, desc));
2134  }
2135 
2136  if (HasOneofFields(desc)) {
2137  printer->Print(
2138  "/**\n"
2139  " * Oneof group definitions for this message. Each group defines the "
2140  "field\n"
2141  " * numbers belonging to that group. When of these fields' value is "
2142  "set, all\n"
2143  " * other fields in the group are cleared. During deserialization, if "
2144  "multiple\n"
2145  " * fields are encountered for a group, only the last value seen will "
2146  "be kept.\n"
2147  " * @private {!Array<!Array<number>>}\n"
2148  " * @const\n"
2149  " */\n"
2150  "$classname$$oneofgrouparray$ = $oneofgroups$;\n"
2151  "\n",
2152  "classname", GetMessagePath(options, desc), "oneofgrouparray",
2153  kOneofGroupArrayName, "oneofgroups", OneofGroupList(desc));
2154 
2155  for (int i = 0; i < desc->oneof_decl_count(); i++) {
2156  if (IgnoreOneof(desc->oneof_decl(i))) {
2157  continue;
2158  }
2159  GenerateOneofCaseDefinition(options, printer, desc->oneof_decl(i));
2160  }
2161  }
2162 }
2163 
2165  io::Printer* printer,
2166  const Descriptor* desc) const {
2167  printer->Print(
2168  "\n"
2169  "\n"
2170  "$class$.prototype.messageXid = xid('$class$');\n",
2171  "class", GetMessagePath(options, desc));
2172 }
2173 
2175  const GeneratorOptions& options, io::Printer* printer,
2176  const OneofDescriptor* oneof) const {
2177  printer->Print(
2178  "/**\n"
2179  " * @enum {number}\n"
2180  " */\n"
2181  "$classname$.$oneof$Case = {\n"
2182  " $upcase$_NOT_SET: 0",
2183  "classname", GetMessagePath(options, oneof->containing_type()), "oneof",
2184  JSOneofName(oneof), "upcase", ToEnumCase(oneof->name()));
2185 
2186  for (int i = 0; i < oneof->field_count(); i++) {
2187  if (IgnoreField(oneof->field(i))) {
2188  continue;
2189  }
2190 
2191  printer->Print(
2192  ",\n"
2193  " $upcase$: $number$",
2194  "upcase", ToEnumCase(oneof->field(i)->name()), "number",
2195  JSFieldIndex(oneof->field(i)));
2196  printer->Annotate("upcase", oneof->field(i));
2197  }
2198 
2199  printer->Print(
2200  "\n"
2201  "};\n"
2202  "\n"
2203  "/**\n"
2204  " * @return {$class$.$oneof$Case}\n"
2205  " */\n"
2206  "$class$.prototype.get$oneof$Case = function() {\n"
2207  " return /** @type {$class$.$oneof$Case} */(jspb.Message."
2208  "computeOneofCase(this, $class$.oneofGroups_[$oneofindex$]));\n"
2209  "};\n"
2210  "\n",
2211  "class", GetMessagePath(options, oneof->containing_type()), "oneof",
2212  JSOneofName(oneof), "oneofindex", JSOneofIndex(oneof));
2213 }
2214 
2216  io::Printer* printer,
2217  const Descriptor* desc) const {
2218  printer->Print(
2219  "\n"
2220  "\n"
2221  "if (jspb.Message.GENERATE_TO_OBJECT) {\n"
2222  "/**\n"
2223  " * Creates an object representation of this proto.\n"
2224  " * Field names that are reserved in JavaScript and will be renamed to "
2225  "pb_name.\n"
2226  " * Optional fields that are not set will be set to undefined.\n"
2227  " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n"
2228  " * For the list of reserved names please see:\n"
2229  " * net/proto2/compiler/js/internal/generator.cc#kKeyword.\n"
2230  " * @param {boolean=} opt_includeInstance Deprecated. whether to include "
2231  "the\n"
2232  " * JSPB instance for transitional soy proto support:\n"
2233  " * http://goto/soy-param-migration\n"
2234  " * @return {!Object}\n"
2235  " */\n"
2236  "$classname$.prototype.toObject = function(opt_includeInstance) {\n"
2237  " return $classname$.toObject(opt_includeInstance, this);\n"
2238  "};\n"
2239  "\n"
2240  "\n"
2241  "/**\n"
2242  " * Static version of the {@see toObject} method.\n"
2243  " * @param {boolean|undefined} includeInstance Deprecated. Whether to "
2244  "include\n"
2245  " * the JSPB instance for transitional soy proto support:\n"
2246  " * http://goto/soy-param-migration\n"
2247  " * @param {!$classname$} msg The msg instance to transform.\n"
2248  " * @return {!Object}\n"
2249  " * @suppress {unusedLocalVariables} f is only used for nested messages\n"
2250  " */\n"
2251  "$classname$.toObject = function(includeInstance, msg) {\n"
2252  " var f, obj = {",
2253  "classname", GetMessagePath(options, desc));
2254 
2255  bool first = true;
2256  for (int i = 0; i < desc->field_count(); i++) {
2257  const FieldDescriptor* field = desc->field(i);
2258  if (IgnoreField(field)) {
2259  continue;
2260  }
2261 
2262  if (!first) {
2263  printer->Print(",\n ");
2264  } else {
2265  printer->Print("\n ");
2266  first = false;
2267  }
2268 
2270  }
2271 
2272  if (!first) {
2273  printer->Print("\n };\n\n");
2274  } else {
2275  printer->Print("\n\n };\n\n");
2276  }
2277 
2278  if (IsExtendable(desc)) {
2279  printer->Print(
2280  " jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), "
2281  "obj,\n"
2282  " $extObject$, $class$.prototype.getExtension,\n"
2283  " includeInstance);\n",
2284  "extObject", JSExtensionsObjectName(options, desc->file(), desc),
2285  "class", GetMessagePath(options, desc));
2286  }
2287 
2288  printer->Print(
2289  " if (includeInstance) {\n"
2290  " obj.$$jspbMessageInstance = msg;\n"
2291  " }\n"
2292  " return obj;\n"
2293  "};\n"
2294  "}\n"
2295  "\n"
2296  "\n",
2297  "classname", GetMessagePath(options, desc));
2298 }
2299 
2301  const char* obj_reference,
2302  const FieldDescriptor* field,
2303  bool use_default) const {
2304  const bool is_float_or_double =
2305  field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
2306  field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE;
2307  const bool is_boolean = field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL;
2308 
2309  const string with_default = use_default ? "WithDefault" : "";
2310  const string default_arg =
2311  use_default ? StrCat(", ", JSFieldDefault(field)) : "";
2312  const string cardinality = field->is_repeated() ? "Repeated" : "";
2313  string type = "";
2314  if (is_float_or_double) {
2315  type = "FloatingPoint";
2316  }
2317  if (is_boolean) {
2318  type = "Boolean";
2319  }
2320 
2321  // Prints the appropriate function, among:
2322  // - getField
2323  // - getBooleanField
2324  // - getFloatingPointField => Replaced by getOptionalFloatingPointField to
2325  // preserve backward compatibility.
2326  // - getFieldWithDefault
2327  // - getBooleanFieldWithDefault
2328  // - getFloatingPointFieldWithDefault
2329  // - getRepeatedField
2330  // - getRepeatedBooleanField
2331  // - getRepeatedFloatingPointField
2332  if (is_float_or_double && !field->is_repeated() && !use_default) {
2333  printer->Print(
2334  "jspb.Message.getOptionalFloatingPointField($obj$, "
2335  "$index$$default$)",
2336  "obj", obj_reference, "index", JSFieldIndex(field), "default",
2337  default_arg);
2338  } else {
2339  printer->Print(
2340  "jspb.Message.get$cardinality$$type$Field$with_default$($obj$, "
2341  "$index$$default$)",
2342  "cardinality", cardinality, "type", type, "with_default", with_default,
2343  "obj", obj_reference, "index", JSFieldIndex(field), "default",
2344  default_arg);
2345  }
2346 }
2347 
2349  io::Printer* printer,
2350  const FieldDescriptor* field) const {
2351  printer->Print("$fieldname$: ", "fieldname",
2352  JSObjectFieldName(options, field));
2353 
2354  if (field->is_map()) {
2355  const FieldDescriptor* value_field = MapFieldValue(field);
2356  // If the map values are of a message type, we must provide their static
2357  // toObject() method; otherwise we pass undefined for that argument.
2358  std::string value_to_object;
2359  if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2360  value_to_object =
2361  GetMessagePath(options, value_field->message_type()) + ".toObject";
2362  } else {
2363  value_to_object = "undefined";
2364  }
2365  printer->Print(
2366  "(f = msg.get$name$()) ? f.toObject(includeInstance, $valuetoobject$) "
2367  ": []",
2368  "name", JSGetterName(options, field), "valuetoobject", value_to_object);
2369  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2370  // Message field.
2371  if (field->is_repeated()) {
2372  {
2373  printer->Print(
2374  "jspb.Message.toObjectList(msg.get$getter$(),\n"
2375  " $type$.toObject, includeInstance)",
2376  "getter", JSGetterName(options, field), "type",
2377  SubmessageTypeRef(options, field));
2378  }
2379  } else {
2380  printer->Print(
2381  "(f = msg.get$getter$()) && "
2382  "$type$.toObject(includeInstance, f)",
2383  "getter", JSGetterName(options, field), "type",
2384  SubmessageTypeRef(options, field));
2385  }
2386  } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
2387  // For bytes fields we want to always return the B64 data.
2388  printer->Print("msg.get$getter$()", "getter",
2389  JSGetterName(options, field, BYTES_B64));
2390  } else {
2391  bool use_default = field->has_default_value();
2392 
2393  if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
2394  // Repeated fields get initialized to their default in the constructor
2395  // (why?), so we emit a plain getField() call for them.
2396  !field->is_repeated() && !UseBrokenPresenceSemantics(options, field)) {
2397  // Proto3 puts all defaults (including implicit defaults) in toObject().
2398  // But for proto2 we leave the existing semantics unchanged: unset fields
2399  // without default are unset.
2400  use_default = true;
2401  }
2402 
2403  // We don't implement this by calling the accessors, because the semantics
2404  // of the accessors are changing independently of the toObject() semantics.
2405  // We are migrating the accessors to return defaults instead of null, but
2406  // it may take longer to migrate toObject (or we might not want to do it at
2407  // all). So we want to generate independent code.
2408  // The accessor for unset optional values without default should return
2409  // null. Those are converted to undefined in the generated object.
2410  if (!use_default) {
2411  printer->Print("(f = ");
2412  }
2413  GenerateFieldValueExpression(printer, "msg", field, use_default);
2414  if (!use_default) {
2415  printer->Print(") == null ? undefined : f");
2416  }
2417  }
2418 }
2419 
2421  io::Printer* printer,
2422  const Descriptor* desc) const {
2423  // TODO(b/122687752): Consider renaming nested messages called ObjectFormat
2424  // to prevent collisions.
2425  const std::string type_name = GetMessagePath(options, desc) + ".ObjectFormat";
2426 
2427  printer->Print(
2428  "/**\n"
2429  " * The raw object form of $messageName$ as accepted by the `fromObject` "
2430  "method.\n"
2431  " * @record\n"
2432  " */\n"
2433  "$typeName$ = function() {\n",
2434  "messageName", desc->name(), "typeName", type_name);
2435 
2436  for (int i = 0; i < desc->field_count(); i++) {
2437  if (i > 0) {
2438  printer->Print("\n");
2439  }
2440  printer->Print(
2441  " /** @type {$fieldType$|undefined} */\n"
2442  " this.$fieldName$;\n",
2443  "fieldName", JSObjectFieldName(options, desc->field(i)),
2444  // TODO(b/121097361): Add type checking for field values.
2445  "fieldType", "?");
2446  }
2447 
2448  printer->Print("};\n\n");
2449 }
2450 
2452  io::Printer* printer,
2453  const Descriptor* desc) const {
2454  printer->Print("if (jspb.Message.GENERATE_FROM_OBJECT) {\n\n");
2455 
2456  GenerateObjectTypedef(options, printer, desc);
2457 
2458  printer->Print(
2459  "/**\n"
2460  " * Loads data from an object into a new instance of this proto.\n"
2461  " * @param {!$classname$.ObjectFormat} obj\n"
2462  " * The object representation of this proto to load the data from.\n"
2463  " * @return {!$classname$}\n"
2464  " */\n"
2465  "$classname$.fromObject = function(obj) {\n"
2466  " var msg = new $classname$();\n",
2467  "classname", GetMessagePath(options, desc));
2468 
2469  for (int i = 0; i < desc->field_count(); i++) {
2470  const FieldDescriptor* field = desc->field(i);
2471  if (!IgnoreField(field)) {
2473  }
2474  }
2475 
2476  printer->Print(
2477  " return msg;\n"
2478  "};\n"
2479  "}\n\n");
2480 }
2481 
2483  const GeneratorOptions& options, io::Printer* printer,
2484  const FieldDescriptor* field) const {
2485  if (field->is_map()) {
2486  const FieldDescriptor* value_field = MapFieldValue(field);
2487  if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
2488  // Since the map values are of message type, we have to do some extra work
2489  // to recursively call fromObject() on them before setting the map field.
2490  printer->Print(
2491  " obj.$name$ && jspb.Message.setWrapperField(\n"
2492  " msg, $index$, jspb.Map.fromObject(obj.$name$, $fieldclass$, "
2493  "$fieldclass$.fromObject));\n",
2494  "name", JSObjectFieldName(options, field), "index",
2495  JSFieldIndex(field), "fieldclass",
2496  GetMessagePath(options, value_field->message_type()));
2497  } else {
2498  // `msg` is a newly-constructed message object that has not yet built any
2499  // map containers wrapping underlying arrays, so we can simply directly
2500  // set the array here without fear of a stale wrapper.
2501  printer->Print(
2502  " obj.$name$ && "
2503  "jspb.Message.setField(msg, $index$, obj.$name$);\n",
2504  "name", JSObjectFieldName(options, field), "index",
2505  JSFieldIndex(field));
2506  }
2507  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2508  // Message field (singular or repeated)
2509  if (field->is_repeated()) {
2510  {
2511  printer->Print(
2512  " obj.$name$ && "
2513  "jspb.Message.setRepeatedWrapperField(\n"
2514  " msg, $index$, obj.$name$.map(\n"
2515  " $fieldclass$.fromObject));\n",
2516  "name", JSObjectFieldName(options, field), "index",
2517  JSFieldIndex(field), "fieldclass",
2518  SubmessageTypeRef(options, field));
2519  }
2520  } else {
2521  printer->Print(
2522  " obj.$name$ && jspb.Message.setWrapperField(\n"
2523  " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
2524  "name", JSObjectFieldName(options, field), "index",
2525  JSFieldIndex(field), "fieldclass", SubmessageTypeRef(options, field));
2526  }
2527  } else {
2528  // Simple (primitive) field.
2529  printer->Print(
2530  " obj.$name$ != null && jspb.Message.setField(msg, $index$, "
2531  "obj.$name$);\n",
2532  "name", JSObjectFieldName(options, field), "index",
2533  JSFieldIndex(field));
2534  }
2535 }
2536 
2538  io::Printer* printer,
2539  const Descriptor* desc) const {
2540  // Register any extensions defined inside this message type.
2541  for (int i = 0; i < desc->extension_count(); i++) {
2542  const FieldDescriptor* extension = desc->extension(i);
2543  if (ShouldGenerateExtension(extension)) {
2544  GenerateExtension(options, printer, extension);
2545  }
2546  }
2547 
2548 }
2549 
2551  io::Printer* printer,
2552  const Descriptor* desc) const {
2553  for (int i = 0; i < desc->field_count(); i++) {
2554  if (!IgnoreField(desc->field(i))) {
2555  GenerateClassField(options, printer, desc->field(i));
2556  }
2557  }
2558 }
2559 
2561  const FieldDescriptor* field, BytesMode bytes_mode) {
2562  std::string type =
2563  JSFieldTypeAnnotation(options, field,
2564  /* is_setter_argument = */ false,
2565  /* force_present = */ false,
2566  /* singular_if_not_packed = */ false, bytes_mode);
2567  printer->Print(
2568  "/**\n"
2569  " * $fielddef$\n"
2570  "$comment$"
2571  " * This is a type-conversion wrapper around `get$defname$()`\n"
2572  " * @return {$type$}\n"
2573  " */\n"
2574  "$class$.prototype.get$name$ = function() {\n"
2575  " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n"
2576  " this.get$defname$()));\n"
2577  "};\n"
2578  "\n"
2579  "\n",
2580  "fielddef", FieldDefinition(options, field), "comment",
2581  FieldComments(field, bytes_mode), "type", type, "class",
2582  GetMessagePath(options, field->containing_type()), "name",
2583  JSGetterName(options, field, bytes_mode), "list",
2584  field->is_repeated() ? "List" : "", "suffix",
2585  JSByteGetterSuffix(bytes_mode), "defname",
2586  JSGetterName(options, field, BYTES_DEFAULT));
2587 }
2588 
2590  io::Printer* printer,
2591  const FieldDescriptor* field) const {
2592  if (field->is_map()) {
2593  const FieldDescriptor* key_field = MapFieldKey(field);
2594  const FieldDescriptor* value_field = MapFieldValue(field);
2595  // Map field: special handling to instantiate the map object on demand.
2597  JSFieldTypeAnnotation(options, key_field,
2598  /* is_setter_argument = */ false,
2599  /* force_present = */ true,
2600  /* singular_if_not_packed = */ false);
2602  JSFieldTypeAnnotation(options, value_field,
2603  /* is_setter_argument = */ false,
2604  /* force_present = */ true,
2605  /* singular_if_not_packed = */ false);
2606 
2607  printer->Print(
2608  "/**\n"
2609  " * $fielddef$\n"
2610  " * @param {boolean=} opt_noLazyCreate Do not create the map if\n"
2611  " * empty, instead returning `undefined`\n"
2612  " * @return {!jspb.Map<$keytype$,$valuetype$>}\n"
2613  " */\n",
2614  "fielddef", FieldDefinition(options, field), "keytype", key_type,
2615  "valuetype", value_type);
2616  printer->Print(
2617  "$class$.prototype.$gettername$ = function(opt_noLazyCreate) {\n"
2618  " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n",
2619  "class", GetMessagePath(options, field->containing_type()),
2620  "gettername", "get" + JSGetterName(options, field), "keytype", key_type,
2621  "valuetype", value_type);
2622  printer->Annotate("gettername", field);
2623  printer->Print(
2624  " jspb.Message.getMapField(this, $index$, opt_noLazyCreate",
2625  "index", JSFieldIndex(field));
2626 
2627  if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
2628  printer->Print(
2629  ",\n"
2630  " $messageType$",
2631  "messageType", GetMessagePath(options, value_field->message_type()));
2632  } else {
2633  printer->Print(
2634  ",\n"
2635  " null");
2636  }
2637 
2638  printer->Print("));\n");
2639 
2640  printer->Print(
2641  "};\n"
2642  "\n"
2643  "\n");
2644  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2645  // Message field: special handling in order to wrap the underlying data
2646  // array with a message object.
2647 
2648  printer->Print(
2649  "/**\n"
2650  " * $fielddef$\n"
2651  "$comment$"
2652  " * @return {$type$}\n"
2653  " */\n",
2654  "fielddef", FieldDefinition(options, field), "comment",
2655  FieldComments(field, BYTES_DEFAULT), "type",
2656  JSFieldTypeAnnotation(options, field,
2657  /* is_setter_argument = */ false,
2658  /* force_present = */ false,
2659  /* singular_if_not_packed = */ false));
2660  printer->Print(
2661  "$class$.prototype.$gettername$ = function() {\n"
2662  " return /** @type{$type$} */ (\n"
2663  " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, "
2664  "$index$$required$));\n"
2665  "};\n"
2666  "\n"
2667  "\n",
2668  "class", GetMessagePath(options, field->containing_type()),
2669  "gettername", "get" + JSGetterName(options, field), "type",
2670  JSFieldTypeAnnotation(options, field,
2671  /* is_setter_argument = */ false,
2672  /* force_present = */ false,
2673  /* singular_if_not_packed = */ false),
2674  "rpt", (field->is_repeated() ? "Repeated" : ""), "index",
2675  JSFieldIndex(field), "wrapperclass", SubmessageTypeRef(options, field),
2676  "required",
2677  (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : ""));
2678  printer->Annotate("gettername", field);
2679  printer->Print(
2680  "/** @param {$optionaltype$} value$returndoc$ */\n"
2681  "$class$.prototype.$settername$ = function(value) {\n"
2682  " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
2683  "optionaltype",
2684  JSFieldTypeAnnotation(options, field,
2685  /* is_setter_argument = */ true,
2686  /* force_present = */ false,
2687  /* singular_if_not_packed = */ false),
2688  "returndoc", JSReturnDoc(options, field), "class",
2689  GetMessagePath(options, field->containing_type()), "settername",
2690  "set" + JSGetterName(options, field), "oneoftag",
2691  (field->containing_oneof() ? "Oneof" : ""), "repeatedtag",
2692  (field->is_repeated() ? "Repeated" : ""));
2693  printer->Annotate("settername", field);
2694 
2695  printer->Print(
2696  "this, $index$$oneofgroup$, value);$returnvalue$\n"
2697  "};\n"
2698  "\n"
2699  "\n",
2700  "index", JSFieldIndex(field), "oneofgroup",
2701  (field->containing_oneof() ? (", " + JSOneofArray(options, field))
2702  : ""),
2703  "returnvalue", JSReturnClause(field));
2704 
2705  if (field->is_repeated()) {
2707  }
2708 
2709  } else {
2710  bool untyped =
2711  false;
2712 
2713  // Simple (primitive) field, either singular or repeated.
2714 
2715  // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type;
2716  // at this point we "lie" to non-binary users and tell the return
2717  // type is always base64 string, pending a LSC to migrate to typed getters.
2718  BytesMode bytes_mode =
2719  field->type() == FieldDescriptor::TYPE_BYTES && !options.binary
2720  ? BYTES_B64
2721  : BYTES_DEFAULT;
2722  std::string typed_annotation =
2723  JSFieldTypeAnnotation(options, field,
2724  /* is_setter_argument = */ false,
2725  /* force_present = */ false,
2726  /* singular_if_not_packed = */ false,
2727  /* bytes_mode = */ bytes_mode);
2728  if (untyped) {
2729  printer->Print(
2730  "/**\n"
2731  " * @return {?} Raw field, untyped.\n"
2732  " */\n");
2733  } else {
2734  printer->Print(
2735  "/**\n"
2736  " * $fielddef$\n"
2737  "$comment$"
2738  " * @return {$type$}\n"
2739  " */\n",
2740  "fielddef", FieldDefinition(options, field), "comment",
2741  FieldComments(field, bytes_mode), "type", typed_annotation);
2742  }
2743 
2744  printer->Print("$class$.prototype.$gettername$ = function() {\n", "class",
2745  GetMessagePath(options, field->containing_type()),
2746  "gettername", "get" + JSGetterName(options, field));
2747  printer->Annotate("gettername", field);
2748 
2749  if (untyped) {
2750  printer->Print(" return ");
2751  } else {
2752  printer->Print(" return /** @type {$type$} */ (", "type",
2753  typed_annotation);
2754  }
2755 
2756  bool use_default = !ReturnsNullWhenUnset(options, field);
2757 
2758  // Raw fields with no default set should just return undefined.
2759  if (untyped && !field->has_default_value()) {
2760  use_default = false;
2761  }
2762 
2763  // Repeated fields get initialized to their default in the constructor
2764  // (why?), so we emit a plain getField() call for them.
2765  if (field->is_repeated()) {
2766  use_default = false;
2767  }
2768 
2769  GenerateFieldValueExpression(printer, "this", field, use_default);
2770 
2771  if (untyped) {
2772  printer->Print(
2773  ";\n"
2774  "};\n"
2775  "\n"
2776  "\n");
2777  } else {
2778  printer->Print(
2779  ");\n"
2780  "};\n"
2781  "\n"
2782  "\n");
2783  }
2784 
2785  if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) {
2786  GenerateBytesWrapper(options, printer, field, BYTES_B64);
2787  GenerateBytesWrapper(options, printer, field, BYTES_U8);
2788  }
2789 
2790  if (untyped) {
2791  printer->Print(
2792  "/**\n"
2793  " * @param {*} value$returndoc$\n"
2794  " */\n",
2795  "returndoc", JSReturnDoc(options, field));
2796  } else {
2797  printer->Print(
2798  "/** @param {$optionaltype$} value$returndoc$ */\n", "optionaltype",
2799  JSFieldTypeAnnotation(options, field,
2800  /* is_setter_argument = */ true,
2801  /* force_present = */ false,
2802  /* singular_if_not_packed = */ false),
2803  "returndoc", JSReturnDoc(options, field));
2804  }
2805 
2806  if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
2807  !field->is_repeated() && !field->is_map() &&
2809  // Proto3 non-repeated and non-map fields without presence use the
2810  // setProto3*Field function.
2811  printer->Print(
2812  "$class$.prototype.$settername$ = function(value) {\n"
2813  " jspb.Message.setProto3$typetag$Field(this, $index$, "
2814  "value);$returnvalue$\n"
2815  "};\n"
2816  "\n"
2817  "\n",
2818  "class", GetMessagePath(options, field->containing_type()),
2819  "settername", "set" + JSGetterName(options, field), "typetag",
2820  JSTypeTag(field), "index", JSFieldIndex(field), "returnvalue",
2821  JSReturnClause(field));
2822  printer->Annotate("settername", field);
2823  } else {
2824  // Otherwise, use the regular setField function.
2825  printer->Print(
2826  "$class$.prototype.$settername$ = function(value) {\n"
2827  " jspb.Message.set$oneoftag$Field(this, $index$",
2828  "class", GetMessagePath(options, field->containing_type()),
2829  "settername", "set" + JSGetterName(options, field), "oneoftag",
2830  (field->containing_oneof() ? "Oneof" : ""), "index",
2831  JSFieldIndex(field));
2832  printer->Annotate("settername", field);
2833  printer->Print(
2834  "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n"
2835  "};\n"
2836  "\n"
2837  "\n",
2838  "type",
2839  untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "",
2840  "typeclose", untyped ? ")" : "", "oneofgroup",
2841  (field->containing_oneof() ? (", " + JSOneofArray(options, field))
2842  : ""),
2843  "returnvalue", JSReturnClause(field), "rptvalueinit",
2844  (field->is_repeated() ? " || []" : ""));
2845  }
2846 
2847  if (untyped) {
2848  printer->Print(
2849  "/**\n"
2850  " * Clears the value.$returndoc$\n"
2851  " */\n",
2852  "returndoc", JSReturnDoc(options, field));
2853  }
2854 
2855  if (field->is_repeated()) {
2857  }
2858  }
2859 
2860  // Generate clearFoo() method for map fields, repeated fields, and other
2861  // fields with presence.
2862  if (field->is_map()) {
2863  // clang-format off
2864  printer->Print(
2865  "/**\n"
2866  " * Clears values from the map. The map will be non-null."
2867  "$returndoc$\n"
2868  " */\n"
2869  "$class$.prototype.$clearername$ = function() {\n"
2870  " this.$gettername$().clear();$returnvalue$\n"
2871  "};\n"
2872  "\n"
2873  "\n",
2874  "returndoc", JSReturnDoc(options, field),
2875  "class", GetMessagePath(options, field->containing_type()),
2876  "clearername", "clear" + JSGetterName(options, field),
2877  "gettername", "get" + JSGetterName(options, field),
2878  "returnvalue", JSReturnClause(field));
2879  // clang-format on
2880  printer->Annotate("clearername", field);
2881  } else if (field->is_repeated() ||
2882  (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
2883  !field->is_required())) {
2884  // Fields where we can delegate to the regular setter.
2885  // clang-format off
2886  printer->Print(
2887  "/**\n"
2888  " * $jsdoc$$returndoc$\n"
2889  " */\n"
2890  "$class$.prototype.$clearername$ = function() {\n"
2891  " this.$settername$($clearedvalue$);$returnvalue$\n"
2892  "};\n"
2893  "\n"
2894  "\n",
2895  "jsdoc", field->is_repeated()
2896  ? "Clears the list making it empty but non-null."
2897  : "Clears the message field making it undefined.",
2898  "returndoc", JSReturnDoc(options, field),
2899  "class", GetMessagePath(options, field->containing_type()),
2900  "clearername", "clear" + JSGetterName(options, field),
2901  "settername", "set" + JSGetterName(options, field),
2902  "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
2903  "returnvalue", JSReturnClause(field));
2904  // clang-format on
2905  printer->Annotate("clearername", field);
2906  } else if (HasFieldPresence(options, field)) {
2907  // Fields where we can't delegate to the regular setter because it doesn't
2908  // accept "undefined" as an argument.
2909  // clang-format off
2910  printer->Print(
2911  "/**\n"
2912  " * Clears the field making it undefined.$returndoc$\n"
2913  " */\n"
2914  "$class$.prototype.$clearername$ = function() {\n"
2915  " jspb.Message.set$maybeoneof$Field(this, "
2916  "$index$$maybeoneofgroup$, ",
2917  "returndoc", JSReturnDoc(options, field),
2918  "class", GetMessagePath(options, field->containing_type()),
2919  "clearername", "clear" + JSGetterName(options, field),
2920  "maybeoneof", (field->containing_oneof() ? "Oneof" : ""),
2921  "maybeoneofgroup", (field->containing_oneof()
2922  ? (", " + JSOneofArray(options, field))
2923  : ""),
2924  "index", JSFieldIndex(field));
2925  // clang-format on
2926  printer->Annotate("clearername", field);
2927  printer->Print(
2928  "$clearedvalue$);$returnvalue$\n"
2929  "};\n"
2930  "\n"
2931  "\n",
2932  "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
2933  "returnvalue", JSReturnClause(field));
2934  }
2935 
2936  if (HasFieldPresence(options, field)) {
2937  printer->Print(
2938  "/**\n"
2939  " * Returns whether this field is set.\n"
2940  " * @return {boolean}\n"
2941  " */\n"
2942  "$class$.prototype.$hasername$ = function() {\n"
2943  " return jspb.Message.getField(this, $index$) != null;\n"
2944  "};\n"
2945  "\n"
2946  "\n",
2947  "class", GetMessagePath(options, field->containing_type()), "hasername",
2948  "has" + JSGetterName(options, field), "index", JSFieldIndex(field));
2949  printer->Annotate("hasername", field);
2950  }
2951 }
2952 
2954  const GeneratorOptions& options, io::Printer* printer,
2955  const FieldDescriptor* field, bool untyped) const {
2956  // clang-format off
2957  printer->Print(
2958  "/**\n"
2959  " * @param {$optionaltype$} value\n"
2960  " * @param {number=} opt_index$returndoc$\n"
2961  " */\n"
2962  "$class$.prototype.$addername$ = function(value, opt_index) {\n"
2963  " jspb.Message.addToRepeatedField(this, $index$",
2964  "class", GetMessagePath(options, field->containing_type()), "addername",
2965  "add" + JSGetterName(options, field, BYTES_DEFAULT,
2966  /* drop_list = */ true),
2967  "optionaltype",
2968  JSFieldTypeAnnotation(
2969  options, field,
2970  /* is_setter_argument = */ false,
2971  /* force_present = */ true,
2972  /* singular_if_not_packed = */ false,
2973  BYTES_DEFAULT,
2974  /* force_singular = */ true),
2975  "index", JSFieldIndex(field),
2976  "returndoc", JSReturnDoc(options, field));
2977  printer->Annotate("addername", field);
2978  printer->Print(
2979  "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, "
2980  "opt_index);$returnvalue$\n"
2981  "};\n"
2982  "\n"
2983  "\n",
2984  "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "",
2985  "typeclose", untyped ? ")" : "", "oneofgroup",
2986  (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""),
2987  "rptvalueinit", "",
2988  "returnvalue", JSReturnClause(field));
2989  // clang-format on
2990 }
2991 
2993  const GeneratorOptions& options, io::Printer* printer,
2994  const FieldDescriptor* field) const {
2995  printer->Print(
2996  "/**\n"
2997  " * @param {!$optionaltype$=} opt_value\n"
2998  " * @param {number=} opt_index\n"
2999  " * @return {!$optionaltype$}\n"
3000  " */\n"
3001  "$class$.prototype.$addername$ = function(opt_value, opt_index) {\n"
3002  " return jspb.Message.addTo$repeatedtag$WrapperField(",
3003  "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "class",
3004  GetMessagePath(options, field->containing_type()), "addername",
3005  "add" + JSGetterName(options, field, BYTES_DEFAULT,
3006  /* drop_list = */ true),
3007  "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
3008 
3009  printer->Annotate("addername", field);
3010  printer->Print(
3011  "this, $index$$oneofgroup$, opt_value, $ctor$, opt_index);\n"
3012  "};\n"
3013  "\n"
3014  "\n",
3015  "index", JSFieldIndex(field), "oneofgroup",
3016  (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""),
3017  "ctor", GetMessagePath(options, field->message_type()));
3018 }
3019 
3021  io::Printer* printer,
3022  const Descriptor* desc) const {
3023  if (IsExtendable(desc)) {
3024  printer->Print(
3025  "\n"
3026  "/**\n"
3027  " * The extensions registered with this message class. This is a "
3028  "map of\n"
3029  " * extension field number to fieldInfo object.\n"
3030  " *\n"
3031  " * For example:\n"
3032  " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
3033  "ctor: proto.example.MyMessage} }\n"
3034  " *\n"
3035  " * fieldName contains the JsCompiler renamed field name property "
3036  "so that it\n"
3037  " * works in OPTIMIZED mode.\n"
3038  " *\n"
3039  " * @type {!Object<number, jspb.ExtensionFieldInfo>}\n"
3040  " */\n"
3041  "$class$.extensions = {};\n"
3042  "\n",
3043  "class", GetMessagePath(options, desc));
3044 
3045  printer->Print(
3046  "\n"
3047  "/**\n"
3048  " * The extensions registered with this message class. This is a "
3049  "map of\n"
3050  " * extension field number to fieldInfo object.\n"
3051  " *\n"
3052  " * For example:\n"
3053  " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
3054  "ctor: proto.example.MyMessage} }\n"
3055  " *\n"
3056  " * fieldName contains the JsCompiler renamed field name property "
3057  "so that it\n"
3058  " * works in OPTIMIZED mode.\n"
3059  " *\n"
3060  " * @type {!Object<number, jspb.ExtensionFieldBinaryInfo>}\n"
3061  " */\n"
3062  "$class$.extensionsBinary = {};\n"
3063  "\n",
3064  "class", GetMessagePath(options, desc));
3065  }
3066 }
3067 
3068 
3070  io::Printer* printer,
3071  const Descriptor* desc) const {
3072  // TODO(cfallin): Handle lazy decoding when requested by field option and/or
3073  // by default for 'bytes' fields and packed repeated fields.
3074 
3075  printer->Print(
3076  "/**\n"
3077  " * Deserializes binary data (in protobuf wire format).\n"
3078  " * @param {jspb.ByteSource} bytes The bytes to deserialize.\n"
3079  " * @return {!$class$}\n"
3080  " */\n"
3081  "$class$.deserializeBinary = function(bytes) {\n"
3082  " var reader = new jspb.BinaryReader(bytes);\n"
3083  " var msg = new $class$;\n"
3084  " return $class$.deserializeBinaryFromReader(msg, reader);\n"
3085  "};\n"
3086  "\n"
3087  "\n"
3088  "/**\n"
3089  " * Deserializes binary data (in protobuf wire format) from the\n"
3090  " * given reader into the given message object.\n"
3091  " * @param {!$class$} msg The message object to deserialize into.\n"
3092  " * @param {!jspb.BinaryReader} reader The BinaryReader to use.\n"
3093  " * @return {!$class$}\n"
3094  " */\n"
3095  "$class$.deserializeBinaryFromReader = function(msg, reader) {\n"
3096  " while (reader.nextField()) {\n",
3097  "class", GetMessagePath(options, desc));
3098  printer->Print(
3099  " if (reader.isEndGroup()) {\n"
3100  " break;\n"
3101  " }\n"
3102  " var field = reader.getFieldNumber();\n"
3103  " switch (field) {\n");
3104 
3105  for (int i = 0; i < desc->field_count(); i++) {
3106  if (!IgnoreField(desc->field(i))) {
3108  }
3109  }
3110 
3111  printer->Print(" default:\n");
3112  if (IsExtendable(desc)) {
3113  printer->Print(
3114  " jspb.Message.readBinaryExtension(msg, reader,\n"
3115  " $extobj$Binary,\n"
3116  " $class$.prototype.getExtension,\n"
3117  " $class$.prototype.setExtension);\n"
3118  " break;\n"
3119  " }\n",
3120  "extobj", JSExtensionsObjectName(options, desc->file(), desc),
3121  "class", GetMessagePath(options, desc));
3122  } else {
3123  printer->Print(
3124  " reader.skipField();\n"
3125  " break;\n"
3126  " }\n");
3127  }
3128 
3129  printer->Print(
3130  " }\n"
3131  " return msg;\n"
3132  "};\n"
3133  "\n"
3134  "\n");
3135 }
3136 
3138  const GeneratorOptions& options, io::Printer* printer,
3139  const FieldDescriptor* field) const {
3140  printer->Print(" case $num$:\n", "num", StrCat(field->number()));
3141 
3142  if (field->is_map()) {
3143  const FieldDescriptor* key_field = MapFieldKey(field);
3144  const FieldDescriptor* value_field = MapFieldValue(field);
3145  printer->Print(
3146  " var value = msg.get$name$();\n"
3147  " reader.readMessage(value, function(message, reader) {\n",
3148  "name", JSGetterName(options, field));
3149 
3150  printer->Print(
3151  " jspb.Map.deserializeBinary(message, reader, "
3152  "$keyReaderFn$, $valueReaderFn$",
3153  "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
3154  "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
3155 
3156  if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
3157  printer->Print(", $messageType$.deserializeBinaryFromReader",
3158  "messageType",
3159  GetMessagePath(options, value_field->message_type()));
3160  } else {
3161  printer->Print(", null");
3162  }
3163  printer->Print(", $defaultKey$", "defaultKey", JSFieldDefault(key_field));
3164  printer->Print(");\n");
3165  printer->Print(" });\n");
3166  } else {
3167  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
3168  printer->Print(
3169  " var value = new $fieldclass$;\n"
3170  " reader.read$msgOrGroup$($grpfield$value,"
3171  "$fieldclass$.deserializeBinaryFromReader);\n",
3172  "fieldclass", SubmessageTypeRef(options, field), "msgOrGroup",
3173  (field->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message",
3174  "grpfield",
3175  (field->type() == FieldDescriptor::TYPE_GROUP)
3176  ? (StrCat(field->number()) + ", ")
3177  : "");
3178  } else {
3179  printer->Print(
3180  " var value = /** @type {$fieldtype$} */ "
3181  "(reader.read$reader$());\n",
3182  "fieldtype",
3183  JSFieldTypeAnnotation(options, field, false, true,
3184  /* singular_if_not_packed */ true, BYTES_U8),
3185  "reader",
3186  JSBinaryReadWriteMethodName(field, /* is_writer = */ false));
3187  }
3188 
3189  if (field->is_repeated() && !field->is_packed()) {
3190  printer->Print(
3191  " msg.add$name$(value);\n", "name",
3192  JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true));
3193  } else {
3194  // Singular fields, and packed repeated fields, receive a |value| either
3195  // as the field's value or as the array of all the field's values; set
3196  // this as the field's value directly.
3197  printer->Print(" msg.set$name$(value);\n", "name",
3198  JSGetterName(options, field));
3199  }
3200  }
3201 
3202  printer->Print(" break;\n");
3203 }
3204 
3206  io::Printer* printer,
3207  const Descriptor* desc) const {
3208  printer->Print(
3209  "/**\n"
3210  " * Serializes the message to binary data (in protobuf wire format).\n"
3211  " * @return {!Uint8Array}\n"
3212  " */\n"
3213  "$class$.prototype.serializeBinary = function() {\n"
3214  " var writer = new jspb.BinaryWriter();\n"
3215  " $class$.serializeBinaryToWriter(this, writer);\n"
3216  " return writer.getResultBuffer();\n"
3217  "};\n"
3218  "\n"
3219  "\n"
3220  "/**\n"
3221  " * Serializes the given message to binary data (in protobuf wire\n"
3222  " * format), writing to the given BinaryWriter.\n"
3223  " * @param {!$class$} message\n"
3224  " * @param {!jspb.BinaryWriter} writer\n"
3225  " * @suppress {unusedLocalVariables} f is only used for nested messages\n"
3226  " */\n"
3227  "$class$.serializeBinaryToWriter = function(message, "
3228  "writer) {\n"
3229  " var f = undefined;\n",
3230  "class", GetMessagePath(options, desc));
3231 
3232  for (int i = 0; i < desc->field_count(); i++) {
3233  if (!IgnoreField(desc->field(i))) {
3234  GenerateClassSerializeBinaryField(options, printer, desc->field(i));
3235  }
3236  }
3237 
3238  if (IsExtendable(desc)) {
3239  printer->Print(
3240  " jspb.Message.serializeBinaryExtensions(message, writer,\n"
3241  " $extobj$Binary, $class$.prototype.getExtension);\n",
3242  "extobj", JSExtensionsObjectName(options, desc->file(), desc), "class",
3243  GetMessagePath(options, desc));
3244  }
3245 
3246  printer->Print(
3247  "};\n"
3248  "\n"
3249  "\n");
3250 }
3251 
3253  const GeneratorOptions& options, io::Printer* printer,
3254  const FieldDescriptor* field) const {
3255  if (HasFieldPresence(options, field) &&
3256  field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
3257  std::string typed_annotation =
3258  JSFieldTypeAnnotation(options, field,
3259  /* is_setter_argument = */ false,
3260  /* force_present = */ false,
3261  /* singular_if_not_packed = */ false,
3262  /* bytes_mode = */ BYTES_DEFAULT);
3263  printer->Print(
3264  " f = /** @type {$type$} */ "
3265  "(jspb.Message.getField(message, $index$));\n",
3266  "index", JSFieldIndex(field), "type", typed_annotation);
3267  } else {
3268  printer->Print(
3269  " f = message.get$name$($nolazy$);\n", "name",
3270  JSGetterName(options, field, BYTES_U8),
3271  // No lazy creation for maps containers -- fastpath the empty case.
3272  "nolazy", field->is_map() ? "true" : "");
3273  }
3274 
3275  // Print an `if (condition)` statement that evaluates to true if the field
3276  // goes on the wire.
3277  if (field->is_map()) {
3278  printer->Print(" if (f && f.getLength() > 0) {\n");
3279  } else if (field->is_repeated()) {
3280  printer->Print(" if (f.length > 0) {\n");
3281  } else {
3282  if (HasFieldPresence(options, field)) {
3283  printer->Print(" if (f != null) {\n");
3284  } else {
3285  // No field presence: serialize onto the wire only if value is
3286  // non-default. Defaults are documented here:
3287  // https://goto.google.com/lhdfm
3288  switch (field->cpp_type()) {
3293  if (IsIntegralFieldWithStringJSType(field)) {
3294  // We can use `parseInt` here even though it will not be precise for
3295  // 64-bit quantities because we are only testing for zero/nonzero,
3296  // and JS numbers (64-bit floating point values, i.e., doubles) are
3297  // integer-precise in the range that includes zero.
3298  printer->Print(" if (parseInt(f, 10) !== 0) {\n");
3299  } else {
3300  printer->Print(" if (f !== 0) {\n");
3301  }
3302  break;
3303  }
3304 
3308  printer->Print(" if (f !== 0.0) {\n");
3309  break;
3311  printer->Print(" if (f) {\n");
3312  break;
3314  printer->Print(" if (f.length > 0) {\n");
3315  break;
3316  default:
3317  assert(false);
3318  break;
3319  }
3320  }
3321  }
3322 
3323  // Write the field on the wire.
3324  if (field->is_map()) {
3325  const FieldDescriptor* key_field = MapFieldKey(field);
3326  const FieldDescriptor* value_field = MapFieldValue(field);
3327  printer->Print(
3328  " f.serializeBinary($index$, writer, "
3329  "$keyWriterFn$, $valueWriterFn$",
3330  "index", StrCat(field->number()), "keyWriterFn",
3331  JSBinaryWriterMethodName(options, key_field), "valueWriterFn",
3332  JSBinaryWriterMethodName(options, value_field));
3333 
3334  if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
3335  printer->Print(", $messageType$.serializeBinaryToWriter", "messageType",
3336  GetMessagePath(options, value_field->message_type()));
3337  }
3338 
3339  printer->Print(");\n");
3340  } else {
3341  printer->Print(
3342  " writer.write$method$(\n"
3343  " $index$,\n"
3344  " f",
3345  "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true),
3346  "index", StrCat(field->number()));
3347 
3348  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
3349  !field->is_map()) {
3350  printer->Print(
3351  ",\n"
3352  " $submsg$.serializeBinaryToWriter\n",
3353  "submsg", SubmessageTypeRef(options, field));
3354  } else {
3355  printer->Print("\n");
3356  }
3357 
3358  printer->Print(" );\n");
3359  }
3360 
3361  // Close the `if`.
3362  printer->Print(" }\n");
3363 }
3364 
3366  io::Printer* printer,
3367  const EnumDescriptor* enumdesc) const {
3368  printer->Print(
3369  "/**\n"
3370  " * @enum {number}\n"
3371  " */\n"
3372  "$enumprefix$$name$ = {\n",
3373  "enumprefix", GetEnumPathPrefix(options, enumdesc), "name",
3374  enumdesc->name());
3375  printer->Annotate("name", enumdesc);
3376 
3377  for (int i = 0; i < enumdesc->value_count(); i++) {
3378  const EnumValueDescriptor* value = enumdesc->value(i);
3379  printer->Print(" $name$: $value$$comma$\n", "name",
3380  ToEnumCase(value->name()), "value",
3381  StrCat(value->number()), "comma",
3382  (i == enumdesc->value_count() - 1) ? "" : ",");
3383  printer->Annotate("name", value);
3384  }
3385 
3386  printer->Print(
3387  "};\n"
3388  "\n");
3389 }
3390 
3392  io::Printer* printer,
3393  const FieldDescriptor* field) const {
3394  std::string extension_scope =
3395  (field->extension_scope()
3396  ? GetMessagePath(options, field->extension_scope())
3397  : GetNamespace(options, field->file()));
3398 
3399  const std::string extension_object_name = JSObjectFieldName(options, field);
3400  printer->Print(
3401  "\n"
3402  "/**\n"
3403  " * A tuple of {field number, class constructor} for the extension\n"
3404  " * field named `$nameInComment$`.\n"
3405  " * @type {!jspb.ExtensionFieldInfo<$extensionType$>}\n"
3406  " */\n"
3407  "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
3408  "nameInComment", extension_object_name, "name", extension_object_name,
3409  "class", extension_scope, "extensionType",
3410  JSFieldTypeAnnotation(options, field,
3411  /* is_setter_argument = */ false,
3412  /* force_present = */ true,
3413  /* singular_if_not_packed = */ false));
3414  printer->Annotate("name", field);
3415  printer->Print(
3416  " $index$,\n"
3417  " {$name$: 0},\n"
3418  " $ctor$,\n"
3419  " /** @type {?function((boolean|undefined),!jspb.Message=): "
3420  "!Object} */ (\n"
3421  " $toObject$),\n"
3422  " $repeated$);\n",
3423  "index", StrCat(field->number()), "name", extension_object_name,
3424  "ctor",
3425  (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
3426  ? SubmessageTypeRef(options, field)
3427  : std::string("null")),
3428  "toObject",
3429  (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
3430  ? (SubmessageTypeRef(options, field) + ".toObject")
3431  : std::string("null")),
3432  "repeated", (field->is_repeated() ? "1" : "0"));
3433 
3434  printer->Print(
3435  "\n"
3436  "$extendName$Binary[$index$] = new jspb.ExtensionFieldBinaryInfo(\n"
3437  " $class$.$name$,\n"
3438  " $binaryReaderFn$,\n"
3439  " $binaryWriterFn$,\n"
3440  " $binaryMessageSerializeFn$,\n"
3441  " $binaryMessageDeserializeFn$,\n",
3442  "extendName",
3443  JSExtensionsObjectName(options, field->file(), field->containing_type()),
3444  "index", StrCat(field->number()), "class", extension_scope, "name",
3445  extension_object_name, "binaryReaderFn",
3446  JSBinaryReaderMethodName(options, field), "binaryWriterFn",
3447  JSBinaryWriterMethodName(options, field), "binaryMessageSerializeFn",
3448  (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
3449  ? (SubmessageTypeRef(options, field) + ".serializeBinaryToWriter")
3450  : "undefined",
3451  "binaryMessageDeserializeFn",
3452  (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
3453  ? (SubmessageTypeRef(options, field) + ".deserializeBinaryFromReader")
3454  : "undefined");
3455 
3456  printer->Print(" $isPacked$);\n", "isPacked",
3457  (field->is_packed() ? "true" : "false"));
3458 
3459  printer->Print(
3460  "// This registers the extension field with the extended class, so that\n"
3461  "// toObject() will function correctly.\n"
3462  "$extendName$[$index$] = $class$.$name$;\n"
3463  "\n",
3464  "extendName",
3465  JSExtensionsObjectName(options, field->file(), field->containing_type()),
3466  "index", StrCat(field->number()), "class", extension_scope, "name",
3467  extension_object_name);
3468 }
3469 
3471  const std::vector<std::pair<std::string, std::string> >& options,
3472  std::string* error) {
3473  for (int i = 0; i < options.size(); i++) {
3474  if (options[i].first == "add_require_for_enums") {
3475  if (options[i].second != "") {
3476  *error = "Unexpected option value for add_require_for_enums";
3477  return false;
3478  }
3479  add_require_for_enums = true;
3480  } else if (options[i].first == "binary") {
3481  if (options[i].second != "") {
3482  *error = "Unexpected option value for binary";
3483  return false;
3484  }
3485  binary = true;
3486  } else if (options[i].first == "testonly") {
3487  if (options[i].second != "") {
3488  *error = "Unexpected option value for testonly";
3489  return false;
3490  }
3491  testonly = true;
3492  } else if (options[i].first == "error_on_name_conflict") {
3493  if (options[i].second != "") {
3494  *error = "Unexpected option value for error_on_name_conflict";
3495  return false;
3496  }
3497  error_on_name_conflict = true;
3498  } else if (options[i].first == "output_dir") {
3499  output_dir = options[i].second;
3500  } else if (options[i].first == "namespace_prefix") {
3501  namespace_prefix = options[i].second;
3502  } else if (options[i].first == "library") {
3503  library = options[i].second;
3504  } else if (options[i].first == "import_style") {
3505  if (options[i].second == "closure") {
3507  } else if (options[i].second == "commonjs") {
3509  } else if (options[i].second == "commonjs_strict") {
3511  } else if (options[i].second == "browser") {
3513  } else if (options[i].second == "es6") {
3515  } else {
3516  *error = "Unknown import style " + options[i].second + ", expected " +
3517  "one of: closure, commonjs, browser, es6.";
3518  }
3519  } else if (options[i].first == "extension") {
3520  extension = options[i].second;
3521  } else if (options[i].first == "one_output_file_per_input_file") {
3522  if (!options[i].second.empty()) {
3523  *error = "Unexpected option value for one_output_file_per_input_file";
3524  return false;
3525  }
3527  } else if (options[i].first == "annotate_code") {
3528  if (!options[i].second.empty()) {
3529  *error = "Unexpected option value for annotate_code";
3530  return false;
3531  }
3532  annotate_code = true;
3533  } else {
3534  // Assume any other option is an output directory, as long as it is a bare
3535  // `key` rather than a `key=value` option.
3536  if (options[i].second != "") {
3537  *error = "Unknown option: " + options[i].first;
3538  return false;
3539  }
3540  output_dir = options[i].first;
3541  }
3542  }
3543 
3544  if (import_style != kImportClosure &&
3545  (add_require_for_enums || testonly || !library.empty() ||
3546  error_on_name_conflict || extension != ".js" ||
3548  *error =
3549  "The add_require_for_enums, testonly, library, error_on_name_conflict, "
3550  "extension, and one_output_file_per_input_file options should only be "
3551  "used for import_style=closure";
3552  return false;
3553  }
3554 
3555  return true;
3556 }
3557 
3559  // We use one output file per input file if we are not using Closure or if
3560  // this is explicitly requested.
3563  }
3564 
3565  // If a library name is provided, we put everything in that one file.
3566  if (!library.empty()) {
3567  return kEverythingInOneFile;
3568  }
3569 
3570  // Otherwise, we create one output file per SCC.
3571  return kOneOutputFilePerSCC;
3572 }
3573 
3575  const GeneratorOptions& options, io::Printer* printer,
3576  const std::vector<const FileDescriptor*>& files) const {
3577  // Build a std::set over all files so that the DFS can detect when it recurses
3578  // into a dep not specified in the user's command line.
3579  std::set<const FileDescriptor*> all_files(files.begin(), files.end());
3580  // Track the in-progress set of files that have been generated already.
3581  std::set<const FileDescriptor*> generated;
3582  for (int i = 0; i < files.size(); i++) {
3583  GenerateFileAndDeps(options, printer, files[i], &all_files, &generated);
3584  }
3585 }
3586 
3588  const GeneratorOptions& options, io::Printer* printer,
3589  const FileDescriptor* root, std::set<const FileDescriptor*>* all_files,
3590  std::set<const FileDescriptor*>* generated) const {
3591  // Skip if already generated.
3592  if (generated->find(root) != generated->end()) {
3593  return;
3594  }
3595  generated->insert(root);
3596 
3597  // Generate all dependencies before this file's content.
3598  for (int i = 0; i < root->dependency_count(); i++) {
3599  const FileDescriptor* dep = root->dependency(i);
3600  GenerateFileAndDeps(options, printer, dep, all_files, generated);
3601  }
3602 
3603  // Generate this file's content. Only generate if the file is part of the
3604  // original set requested to be generated; i.e., don't take all transitive
3605  // deps down to the roots.
3606  if (all_files->find(root) != all_files->end()) {
3608  }
3609 }
3610 
3612  const GeneratorOptions& options,
3613  GeneratorContext* context,
3614  bool use_short_name) const {
3615  std::string filename =
3616  options.output_dir + "/" +
3617  GetJSFilename(options, use_short_name
3618  ? file->name().substr(file->name().rfind('/'))
3619  : file->name());
3620  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
3622  GeneratedCodeInfo annotations;
3624  &annotations);
3625  io::Printer printer(output.get(), '$',
3626  options.annotate_code ? &annotation_collector : nullptr);
3627 
3628  GenerateFile(options, &printer, file);
3629 
3630  if (printer.failed()) {
3631  return false;
3632  }
3633 
3634  if (options.annotate_code) {
3635  EmbedCodeAnnotations(annotations, &printer);
3636  }
3637 
3638  return true;
3639 }
3640 
3642  io::Printer* printer,
3643  const FileDescriptor* file) const {
3644  GenerateHeader(options, file, printer);
3645 
3646  // Generate "require" statements.
3647  if ((options.import_style == GeneratorOptions::kImportCommonJs ||
3649  printer->Print("var jspb = require('google-protobuf');\n");
3650  printer->Print("var goog = jspb;\n");
3651 
3652  // Do not use global scope in strict mode
3653  if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
3654  printer->Print("var proto = {};\n\n");
3655  } else {
3656  printer->Print("var global = Function('return this')();\n\n");
3657  }
3658 
3659  for (int i = 0; i < file->dependency_count(); i++) {
3660  const std::string& name = file->dependency(i)->name();
3661  printer->Print(
3662  "var $alias$ = require('$file$');\n"
3663  "goog.object.extend(proto, $alias$);\n",
3664  "alias", ModuleAlias(name), "file",
3665  GetRootPath(file->name(), name) + GetJSFilename(options, name));
3666  }
3667  }
3668 
3669  std::set<std::string> provided;
3670  std::set<const FieldDescriptor*> extensions;
3671  for (int i = 0; i < file->extension_count(); i++) {
3672  // We honor the jspb::ignore option here only when working with
3673  // Closure-style imports. Use of this option is discouraged and so we want
3674  // to avoid adding new support for it.
3675  if (options.import_style == GeneratorOptions::kImportClosure &&
3676  IgnoreField(file->extension(i))) {
3677  continue;
3678  }
3679  provided.insert(GetNamespace(options, file) + "." +
3680  JSObjectFieldName(options, file->extension(i)));
3681  extensions.insert(file->extension(i));
3682  }
3683 
3684  FindProvidesForFile(options, printer, file, &provided);
3685  GenerateProvides(options, printer, &provided);
3686  std::vector<const FileDescriptor*> files;
3687  files.push_back(file);
3688  if (options.import_style == GeneratorOptions::kImportClosure) {
3689  GenerateRequiresForLibrary(options, printer, files, &provided);
3690  }
3691 
3692  GenerateClassesAndEnums(options, printer, file);
3693 
3694  // Generate code for top-level extensions. Extensions nested inside messages
3695  // are emitted inside GenerateClassesAndEnums().
3696  for (std::set<const FieldDescriptor*>::const_iterator it = extensions.begin();
3697  it != extensions.end(); ++it) {
3698  GenerateExtension(options, printer, *it);
3699  }
3700 
3701  // if provided is empty, do not export anything
3702  if (options.import_style == GeneratorOptions::kImportCommonJs &&
3703  !provided.empty()) {
3704  printer->Print("goog.object.extend(exports, $package$);\n", "package",
3705  GetNamespace(options, file));
3706  } else if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
3707  printer->Print("goog.object.extend(exports, proto);\n", "package",
3708  GetNamespace(options, file));
3709  }
3710 
3711  // Emit well-known type methods.
3712  for (FileToc* toc = well_known_types_js; toc->name != NULL; toc++) {
3713  std::string name = std::string("google/protobuf/") + toc->name;
3714  if (name == StripProto(file->name()) + ".js") {
3715  printer->Print(toc->data);
3716  }
3717  }
3718 }
3719 
3720 bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
3721  const std::string& parameter,
3722  GeneratorContext* context,
3723  std::string* error) const {
3724  std::vector<std::pair<std::string, std::string> > option_pairs;
3725  ParseGeneratorParameter(parameter, &option_pairs);
3727  if (!options.ParseFromOptions(option_pairs, error)) {
3728  return false;
3729  }
3730 
3731 
3732  if (options.output_mode() == GeneratorOptions::kEverythingInOneFile) {
3733  // All output should go in a single file.
3734  std::string filename = options.output_dir + "/" + options.library +
3735  options.GetFileNameExtension();
3736  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
3737  GOOGLE_CHECK(output.get());
3738  GeneratedCodeInfo annotations;
3740  &annotations);
3741  io::Printer printer(
3742  output.get(), '$',
3743  options.annotate_code ? &annotation_collector : nullptr);
3744 
3745  // Pull out all extensions -- we need these to generate all
3746  // provides/requires.
3747  std::vector<const FieldDescriptor*> extensions;
3748  for (int i = 0; i < files.size(); i++) {
3749  for (int j = 0; j < files[i]->extension_count(); j++) {
3750  const FieldDescriptor* extension = files[i]->extension(j);
3751  extensions.push_back(extension);
3752  }
3753  }
3754 
3755  if (files.size() == 1) {
3756  GenerateHeader(options, files[0], &printer);
3757  } else {
3758  GenerateHeader(options, nullptr, &printer);
3759  }
3760 
3761  std::set<std::string> provided;
3762  FindProvides(options, &printer, files, &provided);
3763  FindProvidesForFields(options, &printer, extensions, &provided);
3764  GenerateProvides(options, &printer, &provided);
3765  GenerateTestOnly(options, &printer);
3766  GenerateRequiresForLibrary(options, &printer, files, &provided);
3767 
3768  GenerateFilesInDepOrder(options, &printer, files);
3769 
3770  for (int i = 0; i < extensions.size(); i++) {
3771  if (ShouldGenerateExtension(extensions[i])) {
3772  GenerateExtension(options, &printer, extensions[i]);
3773  }
3774  }
3775 
3776  if (printer.failed()) {
3777  return false;
3778  }
3779  if (options.annotate_code) {
3780  EmbedCodeAnnotations(annotations, &printer);
3781  }
3782  } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerSCC) {
3783  std::set<const Descriptor*> have_printed;
3784  SCCAnalyzer<DepsGenerator> analyzer;
3785  std::map<const void*, std::string> allowed_map;
3786  if (!GenerateJspbAllowedMap(options, files, &allowed_map, &analyzer,
3787  error)) {
3788  return false;
3789  }
3790 
3791  bool generated = false;
3792  for (int i = 0; i < files.size(); i++) {
3793  const FileDescriptor* file = files[i];
3794  // Force well known type to generate in a whole file.
3795  if (IsWellKnownTypeFile(file)) {
3796  if (!GenerateFile(file, options, context, true)) {
3797  return false;
3798  }
3799  generated = true;
3800  continue;
3801  }
3802  for (int j = 0; j < file->message_type_count(); j++) {
3803  const Descriptor* desc = file->message_type(j);
3804  if (have_printed.count(desc) ||
3805  allowed_map.count(analyzer.GetSCC(desc)) == 0) {
3806  continue;
3807  }
3808 
3809  generated = true;
3810  const SCC* scc = analyzer.GetSCC(desc);
3811  const std::string& filename = allowed_map[scc];
3812  std::unique_ptr<io::ZeroCopyOutputStream> output(
3813  context->Open(filename));
3814  GOOGLE_CHECK(output.get());
3815  GeneratedCodeInfo annotations;
3817  &annotations);
3818  io::Printer printer(
3819  output.get(), '$',
3820  options.annotate_code ? &annotation_collector : nullptr);
3821 
3822  GenerateHeader(options, file, &printer);
3823 
3824  std::set<std::string> provided;
3825  for (auto one_desc : scc->descriptors) {
3826  if (one_desc->containing_type() == nullptr) {
3827  FindProvidesForMessage(options, &printer, one_desc, &provided);
3828  }
3829  }
3830  GenerateProvides(options, &printer, &provided);
3831  GenerateTestOnly(options, &printer);
3832  GenerateRequiresForSCC(options, &printer, scc, &provided);
3833 
3834  for (auto one_desc : scc->descriptors) {
3835  if (one_desc->containing_type() == nullptr) {
3837  options, &printer, one_desc);
3838  }
3839  }
3840  for (auto one_desc : scc->descriptors) {
3841  if (one_desc->containing_type() == nullptr) {
3842  GenerateClass(options, &printer, one_desc);
3843  }
3844  }
3845 
3846  for (auto one_desc : scc->descriptors) {
3847  have_printed.insert(one_desc);
3848  }
3849 
3850  if (printer.failed()) {
3851  return false;
3852  }
3853  if (options.annotate_code) {
3854  EmbedCodeAnnotations(annotations, &printer);
3855  }
3856  }
3857  for (int j = 0; j < file->enum_type_count(); j++) {
3858  const EnumDescriptor* enumdesc = file->enum_type(j);
3859  if (allowed_map.count(enumdesc) == 0) {
3860  continue;
3861  }
3862 
3863  generated = true;
3864  const std::string& filename = allowed_map[enumdesc];
3865  std::unique_ptr<io::ZeroCopyOutputStream> output(
3866  context->Open(filename));
3867  GOOGLE_CHECK(output.get());
3868  GeneratedCodeInfo annotations;
3870  &annotations);
3871  io::Printer printer(
3872  output.get(), '$',
3873  options.annotate_code ? &annotation_collector : nullptr);
3874 
3875  GenerateHeader(options, file, &printer);
3876 
3877  std::set<std::string> provided;
3878  FindProvidesForEnum(options, &printer, enumdesc, &provided);
3879  GenerateProvides(options, &printer, &provided);
3880  GenerateTestOnly(options, &printer);
3881 
3882  GenerateEnum(options, &printer, enumdesc);
3883 
3884  if (printer.failed()) {
3885  return false;
3886  }
3887  if (options.annotate_code) {
3888  EmbedCodeAnnotations(annotations, &printer);
3889  }
3890  }
3891  // File-level extensions (message-level extensions are generated under
3892  // the enclosing message).
3893  if (allowed_map.count(file) == 1) {
3894  generated = true;
3895  const std::string& filename = allowed_map[file];
3896 
3897  std::unique_ptr<io::ZeroCopyOutputStream> output(
3898  context->Open(filename));
3899  GOOGLE_CHECK(output.get());
3900  GeneratedCodeInfo annotations;
3902  &annotations);
3903  io::Printer printer(
3904  output.get(), '$',
3905  options.annotate_code ? &annotation_collector : nullptr);
3906 
3907  GenerateHeader(options, file, &printer);
3908 
3909  std::set<std::string> provided;
3910  std::vector<const FieldDescriptor*> fields;
3911 
3912  for (int j = 0; j < files[i]->extension_count(); j++) {
3913  if (ShouldGenerateExtension(files[i]->extension(j))) {
3914  fields.push_back(files[i]->extension(j));
3915  }
3916  }
3917 
3918  FindProvidesForFields(options, &printer, fields, &provided);
3919  GenerateProvides(options, &printer, &provided);
3920  GenerateTestOnly(options, &printer);
3921  GenerateRequiresForExtensions(options, &printer, fields, &provided);
3922 
3923  for (int j = 0; j < files[i]->extension_count(); j++) {
3924  if (ShouldGenerateExtension(files[i]->extension(j))) {
3925  GenerateExtension(options, &printer, files[i]->extension(j));
3926  }
3927  }
3928  if (options.annotate_code) {
3929  EmbedCodeAnnotations(annotations, &printer);
3930  }
3931  }
3932  }
3933  if (!generated) {
3934  std::string filename = options.output_dir + "/" +
3935  "empty_no_content_void_file" +
3936  options.GetFileNameExtension();
3937  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
3938  }
3939  } else /* options.output_mode() == kOneOutputFilePerInputFile */ {
3940  // Generate one output file per input (.proto) file.
3941 
3942  for (int i = 0; i < files.size(); i++) {
3943  const FileDescriptor* file = files[i];
3944  if (!GenerateFile(file, options, context, false)) {
3945  return false;
3946  }
3947  }
3948  }
3949  return true;
3950 }
3951 
3952 } // namespace js
3953 } // namespace compiler
3954 } // namespace protobuf
3955 } // namespace google
zero_copy_stream.h
google::protobuf::io::Printer::Print
void Print(const std::map< std::string, std::string > &variables, const char *text)
Definition: printer.cc:112
google::protobuf::compiler::js::Generator::GenerateOneofCaseDefinition
void GenerateOneofCaseDefinition(const GeneratorOptions &options, io::Printer *printer, const OneofDescriptor *oneof) const
Definition: js_generator.cc:2174
GOOGLE_CHECK_EQ
#define GOOGLE_CHECK_EQ(A, B)
Definition: logging.h:156
google::protobuf::compiler::js::GeneratorOptions::OutputMode
OutputMode
Definition: js_generator.h:100
google::protobuf::FieldDescriptor::TYPE_SINT64
@ TYPE_SINT64
Definition: src/google/protobuf/descriptor.h:544
google::protobuf::FieldDescriptor::CPPTYPE_ENUM
@ CPPTYPE_ENUM
Definition: src/google/protobuf/descriptor.h:561
FileToc::name
const char * name
Definition: well_known_types_embed.h:37
name
GLuint const GLchar * name
Definition: glcorearb.h:3055
google::protobuf::compiler::js::Generator::GenerateFile
bool GenerateFile(const FileDescriptor *file, const GeneratorOptions &options, GeneratorContext *context, bool use_short_name) const
Definition: js_generator.cc:3611
FieldOptions::JS_STRING
static constexpr JSType JS_STRING
Definition: descriptor.pb.h:4231
google::protobuf::compiler::js::GeneratorOptions::kImportCommonJs
@ kImportCommonJs
Definition: js_generator.h:72
google::protobuf::FieldDescriptor::CPPTYPE_STRING
@ CPPTYPE_STRING
Definition: src/google/protobuf/descriptor.h:562
google::protobuf::FieldDescriptor
Definition: src/google/protobuf/descriptor.h:515
google::protobuf::FileDescriptor::enum_type
const EnumDescriptor * enum_type(int index) const
google::protobuf::compiler::js::kNumKeyword
static const int kNumKeyword
Definition: js_generator.cc:77
google::protobuf::SimpleDtoa
string SimpleDtoa(double value)
Definition: strutil.cc:1219
allowed_descs_full_name_
std::map< const void *, std::string > allowed_descs_full_name_
Definition: js_generator.cc:1489
google::protobuf::extension
const Descriptor::ReservedRange const EnumValueDescriptor const MethodDescriptor extension
Definition: src/google/protobuf/descriptor.h:2001
google::protobuf::compiler::js::GeneratorOptions::output_mode
OutputMode output_mode() const
Definition: js_generator.cc:3558
google::protobuf::compiler::SCC
Definition: scc.h:49
NULL
NULL
Definition: test_security_zap.cpp:405
running
static std::atomic< bool > running
Definition: network.cpp:48
google::protobuf::int64
int64_t int64
Definition: protobuf/src/google/protobuf/stubs/port.h:151
allowed_descs_actual_name_
std::map< const void *, std::string > allowed_descs_actual_name_
Definition: js_generator.cc:1487
google::protobuf::StrCat
string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: strutil.cc:1480
google::protobuf::compiler::cpp::StripProto
std::string StripProto(const std::string &filename)
Definition: cpp_helpers.cc:474
google::protobuf::FieldDescriptor::TYPE_SINT32
@ TYPE_SINT32
Definition: src/google/protobuf/descriptor.h:543
google::protobuf::FieldDescriptor::CPPTYPE_UINT64
@ CPPTYPE_UINT64
Definition: src/google/protobuf/descriptor.h:557
google::protobuf::compiler::js::GeneratorOptions
Definition: js_generator.h:62
length
GLenum GLuint GLenum GLsizei length
Definition: glcorearb.h:2695
google::protobuf::compiler::js::Generator::GenerateExtension
void GenerateExtension(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field) const
Definition: js_generator.cc:3391
google::protobuf::compiler::js::Generator::GenerateClassConstructor
void GenerateClassConstructor(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2055
options
Message * options
Definition: src/google/protobuf/descriptor.cc:3119
input
std::string input
Definition: tokenizer_unittest.cc:197
google::protobuf::uint8
uint8_t uint8
Definition: protobuf/src/google/protobuf/stubs/port.h:153
google::protobuf::compiler::js::Generator::GenerateClassFields
void GenerateClassFields(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2550
google::protobuf::EnumDescriptor::value_count
int value_count() const
FATAL
const int FATAL
Definition: log_severity.h:60
google::protobuf::FieldDescriptor::TYPE_BYTES
@ TYPE_BYTES
Definition: src/google/protobuf/descriptor.h:538
google::protobuf::compiler::js::Generator::GenerateClassField
void GenerateClassField(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *desc) const
Definition: js_generator.cc:2589
google::protobuf::compiler::js::Generator::GenerateTestOnly
void GenerateTestOnly(const GeneratorOptions &options, io::Printer *printer) const
Definition: js_generator.cc:1989
google::protobuf::FieldDescriptor::CPPTYPE_INT64
@ CPPTYPE_INT64
Definition: src/google/protobuf/descriptor.h:555
google::protobuf::compiler::GeneratorContext::Open
virtual io::ZeroCopyOutputStream * Open(const std::string &filename)=0
FileDescriptor
Definition: ruby/ext/google/protobuf_c/protobuf.h:125
google::protobuf::FieldDescriptor::CPPTYPE_UINT32
@ CPPTYPE_UINT32
Definition: src/google/protobuf/descriptor.h:556
google::protobuf::Descriptor::containing_type
const Descriptor * containing_type() const
google::protobuf::compiler::annotation_test_util::AddFile
void AddFile(const std::string &filename, const std::string &data)
Definition: annotation_test_util.cc:72
desc
#define desc
Definition: extension_set.h:342
google::protobuf::compiler::js::Generator::GenerateClassToObject
void GenerateClassToObject(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2215
google::protobuf::OneofDescriptor
Definition: src/google/protobuf/descriptor.h:843
google::protobuf::compiler::js::Generator::GenerateEnum
void GenerateEnum(const GeneratorOptions &options, io::Printer *printer, const EnumDescriptor *enumdesc) const
Definition: js_generator.cc:3365
string
GLsizei const GLchar *const * string
Definition: glcorearb.h:3083
scc.h
google::protobuf::compiler::js::Generator::GenerateClassSerializeBinary
void GenerateClassSerializeBinary(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:3205
google::protobuf::StringPiece::substr
StringPiece substr(size_type pos, size_type n=npos) const
Definition: stringpiece.cc:261
google::protobuf::ReplaceCharacters
void ReplaceCharacters(string *s, const char *remove, char replacewith)
Definition: strutil.cc:103
well_known_types_js
struct FileToc well_known_types_js[]
Definition: well_known_types_embed.cc:33
descriptor
Descriptor * descriptor
Definition: php/ext/google/protobuf/protobuf.h:936
google::protobuf::OneofDescriptor::name
const std::string & name() const
google::protobuf::FileDescriptor::SYNTAX_PROTO2
@ SYNTAX_PROTO2
Definition: src/google/protobuf/descriptor.h:1393
x
GLint GLenum GLint x
Definition: glcorearb.h:2834
google::protobuf::compiler::js::Generator::FindProvides
void FindProvides(const GeneratorOptions &options, io::Printer *printer, const std::vector< const FileDescriptor * > &file, std::set< std::string > *provided) const
Definition: js_generator.cc:1685
google::protobuf::compiler::js::Generator::GenerateObjectTypedef
void GenerateObjectTypedef(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2420
google::protobuf::compiler::js::GenerateBytesWrapper
void GenerateBytesWrapper(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field, BytesMode bytes_mode)
Definition: js_generator.cc:2560
error
Definition: cJSON.c:88
google::protobuf::OneofDescriptor::field
const FieldDescriptor * field(int index) const
Definition: src/google/protobuf/descriptor.h:2179
Descriptor
Definition: ruby/ext/google/protobuf_c/protobuf.h:113
bytes
uint8 bytes[10]
Definition: coded_stream_unittest.cc:153
google::protobuf::compiler::js::GeneratorOptions::library
std::string library
Definition: js_generator.h:121
google::protobuf::compiler::js::Generator::GenerateClassXid
void GenerateClassXid(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2164
google::protobuf::FileDescriptor::enum_type_count
int enum_type_count() const
google::protobuf::compiler::js::GeneratorOptions::output_dir
std::string output_dir
Definition: js_generator.h:64
error_on_conflict_
bool error_on_conflict_
Definition: js_generator.cc:1483
google::protobuf::compiler::js::Generator::GenerateClassesAndEnums
void GenerateClassesAndEnums(const GeneratorOptions &options, io::Printer *printer, const FileDescriptor *file) const
Definition: js_generator.cc:1997
google::protobuf::compiler::SCC::GetRepresentative
const Descriptor * GetRepresentative() const
Definition: scc.h:53
google::protobuf::compiler::js::GeneratorOptions::kImportBrowser
@ kImportBrowser
Definition: js_generator.h:74
google::protobuf::compiler::js::Generator::GenerateClassSerializeBinaryField
void GenerateClassSerializeBinaryField(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field) const
Definition: js_generator.cc:3252
google::protobuf::compiler::js::GeneratorOptions::kImportEs6
@ kImportEs6
Definition: js_generator.h:75
google::protobuf::compiler::js::GeneratorOptions::namespace_prefix
std::string namespace_prefix
Definition: js_generator.h:66
key_type
upb_fieldtype_t key_type
Definition: php/ext/google/protobuf/protobuf.h:1062
google::protobuf::FileDescriptor::package
const std::string & package() const
google::protobuf::Descriptor::field
const FieldDescriptor * field(int index) const
google::protobuf::int32
int32_t int32
Definition: protobuf/src/google/protobuf/stubs/port.h:150
google::protobuf::python::message_descriptor::IsExtendable
static PyObject * IsExtendable(PyBaseDescriptor *self, void *closure)
Definition: python/google/protobuf/pyext/descriptor.cc:550
package
string package
google::protobuf::FieldDescriptor::LABEL_REQUIRED
@ LABEL_REQUIRED
Definition: src/google/protobuf/descriptor.h:573
google::protobuf::compiler::js::GeneratorOptions::kOneOutputFilePerInputFile
@ kOneOutputFilePerInputFile
Definition: js_generator.h:102
google::protobuf::EnumDescriptor::name
const std::string & name() const
google::protobuf::compiler::js::Generator::FindRequiresForMessage
void FindRequiresForMessage(const GeneratorOptions &options, const Descriptor *desc, std::set< std::string > *required, std::set< std::string > *forwards, bool *have_message) const
Definition: js_generator.cc:1929
strutil.h
google::protobuf::FieldDescriptor::TYPE_UINT32
@ TYPE_UINT32
Definition: src/google/protobuf/descriptor.h:539
mingw.root
def root(location=None, arch=None, version=None, threading=None, exceptions=None, revision=None, log=EmptyLogger())
Definition: mingw.py:172
google::protobuf::compiler::js::GeneratorOptions::testonly
bool testonly
Definition: js_generator.h:118
prefix
static const char prefix[]
Definition: test_pair_ipc.cpp:26
google::protobuf::compiler::js::Generator::FindProvidesForFile
void FindProvidesForFile(const GeneratorOptions &options, io::Printer *printer, const FileDescriptor *file, std::set< std::string > *provided) const
Definition: js_generator.cc:1673
google::protobuf::compiler::js::kKeyword
const char * kKeyword[]
Definition: js_generator.cc:62
google::protobuf::StringPiece
Definition: stringpiece.h:180
google::protobuf::uint16
uint16_t uint16
Definition: protobuf/src/google/protobuf/stubs/port.h:154
FileToc
Definition: well_known_types_embed.h:36
google::protobuf::compiler::js::NamespaceOnly
bool NamespaceOnly(const Descriptor *desc)
Definition: js_generator.cc:1925
google::protobuf::Descriptor::oneof_decl
const OneofDescriptor * oneof_decl(int index) const
google::protobuf::StripPrefixString
string StripPrefixString(const string &str, const string &prefix)
Definition: strutil.h:121
google::protobuf::compiler::SCCAnalyzer::GetSCC
const SCC * GetSCC(const Descriptor *descriptor)
Definition: scc.h:67
google::protobuf::EnumDescriptor::value
const EnumValueDescriptor * value(int index) const
google::protobuf::compiler::js::Generator::GenerateRequiresImpl
void GenerateRequiresImpl(const GeneratorOptions &options, io::Printer *printer, std::set< std::string > *required, std::set< std::string > *forwards, std::set< std::string > *provided, bool require_jspb, bool require_extension, bool require_map) const
Definition: js_generator.cc:1887
printer.h
google::protobuf::FieldDescriptor::number
int number() const
GOOGLE_LOG
#define GOOGLE_LOG(LEVEL)
Definition: logging.h:146
google::protobuf::FieldDescriptor::TYPE_BOOL
@ TYPE_BOOL
Definition: src/google/protobuf/descriptor.h:533
well_known_types_embed.h
google::protobuf::io::Printer::failed
bool failed() const
Definition: printer.h:288
google::protobuf::uint64
uint64_t uint64
Definition: protobuf/src/google/protobuf/stubs/port.h:156
google::protobuf::compiler::js::Generator::GenerateClassFieldInfo
void GenerateClassFieldInfo(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2119
google::protobuf::WARNING
static const LogLevel WARNING
Definition: protobuf/src/google/protobuf/testing/googletest.h:71
google::protobuf::FieldDescriptor::TYPE_STRING
@ TYPE_STRING
Definition: src/google/protobuf/descriptor.h:534
google::protobuf::compiler::js::GeneratorOptions::one_output_file_per_input_file
bool one_output_file_per_input_file
Definition: js_generator.h:127
google::protobuf::compiler::js::Generator::GenerateClassDeserializeBinaryField
void GenerateClassDeserializeBinaryField(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field) const
Definition: js_generator.cc:3137
google::protobuf::compiler::js::Generator::GenerateRequiresForLibrary
void GenerateRequiresForLibrary(const GeneratorOptions &options, io::Printer *printer, const std::vector< const FileDescriptor * > &files, std::set< std::string > *provided) const
Definition: js_generator.cc:1818
google::protobuf::compiler::js::FindProvidesForOneOfEnums
void FindProvidesForOneOfEnums(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc, std::set< std::string > *provided)
Definition: js_generator.cc:1704
google::protobuf::compiler::js::Generator::GenerateHeader
void GenerateHeader(const GeneratorOptions &options, const FileDescriptor *file, io::Printer *printer) const
Definition: js_generator.cc:1653
google::protobuf::Descriptor::field_count
int field_count() const
d
d
google::protobuf::compiler::js::GeneratorOptions::kOneOutputFilePerSCC
@ kOneOutputFilePerSCC
Definition: js_generator.h:104
EnumDescriptor
Definition: ruby/ext/google/protobuf_c/protobuf.h:137
google::protobuf::FileDescriptor::SYNTAX_PROTO3
@ SYNTAX_PROTO3
Definition: src/google/protobuf/descriptor.h:1394
google::protobuf::StringPrintf
string StringPrintf(const char *format,...)
Definition: stringprintf.cc:109
google::protobuf::HasPrefixString
bool HasPrefixString(const string &str, const string &prefix)
Definition: strutil.h:115
google::protobuf::SimpleFtoa
string SimpleFtoa(float value)
Definition: strutil.cc:1224
testing::internal::ToLower
char ToLower(char ch)
Definition: gtest-port.h:2025
field
const FieldDescriptor * field
Definition: parser_unittest.cc:2694
google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE
@ CPPTYPE_DOUBLE
Definition: src/google/protobuf/descriptor.h:558
descs_by_shortname_
std::map< std::string, const void * > descs_by_shortname_
Definition: js_generator.cc:1485
google::protobuf::io::Printer::Annotate
void Annotate(const char *varname, const SomeDescriptor *descriptor)
Definition: printer.h:199
google::protobuf::compiler::js::Generator::GenerateRequiresForSCC
void GenerateRequiresForSCC(const GeneratorOptions &options, io::Printer *printer, const SCC *scc, std::set< std::string > *provided) const
Definition: js_generator.cc:1795
GOOGLE_CHECK
#define GOOGLE_CHECK(EXPRESSION)
Definition: logging.h:153
google::protobuf::io::Printer
Definition: printer.h:181
i
int i
Definition: gmock-matchers_test.cc:764
google::protobuf::compiler::js::Generator::GenerateFileAndDeps
void GenerateFileAndDeps(const GeneratorOptions &options, io::Printer *printer, const FileDescriptor *root, std::set< const FileDescriptor * > *all_files, std::set< const FileDescriptor * > *generated) const
Definition: js_generator.cc:3587
google::protobuf::FieldDescriptor::TYPE_MESSAGE
@ TYPE_MESSAGE
Definition: src/google/protobuf/descriptor.h:536
google::protobuf::FieldDescriptor::TYPE_DOUBLE
@ TYPE_DOUBLE
Definition: src/google/protobuf/descriptor.h:522
google::protobuf::FileDescriptor::name
const std::string & name() const
fields
static const upb_fielddef fields[107]
Definition: ruby/ext/google/protobuf_c/upb.c:7671
google::protobuf::FieldDescriptor::CPPTYPE_FLOAT
@ CPPTYPE_FLOAT
Definition: src/google/protobuf/descriptor.h:559
type
GLenum type
Definition: glcorearb.h:2695
google::protobuf::FieldDescriptor::CPPTYPE_BOOL
@ CPPTYPE_BOOL
Definition: src/google/protobuf/descriptor.h:560
google::protobuf::FieldDescriptor::TYPE_INT32
@ TYPE_INT32
Definition: src/google/protobuf/descriptor.h:528
google::protobuf::compiler::js::Generator::FindProvidesForFields
void FindProvidesForFields(const GeneratorOptions &options, io::Printer *printer, const std::vector< const FieldDescriptor * > &fields, std::set< std::string > *provided) const
Definition: js_generator.cc:1746
google::protobuf::FieldDescriptor::TYPE_FLOAT
@ TYPE_FLOAT
Definition: src/google/protobuf/descriptor.h:523
google::protobuf::FieldDescriptor::type
Type type() const
Definition: src/google/protobuf/descriptor.h:2052
google::protobuf::compiler::js::Generator::GenerateClassDeserializeBinary
void GenerateClassDeserializeBinary(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:3069
google::protobuf::compiler::js::GeneratorOptions::ParseFromOptions
bool ParseFromOptions(const std::vector< std::pair< std::string, std::string > > &options, std::string *error)
Definition: js_generator.cc:3470
google::protobuf::compiler::js::Generator::GenerateRepeatedPrimitiveHelperMethods
void GenerateRepeatedPrimitiveHelperMethods(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field, bool untyped) const
Definition: js_generator.cc:2953
file_set_
const std::set< const FileDescriptor * > & file_set_
Definition: js_generator.cc:1520
google::protobuf::Base64Escape
int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest)
Definition: strutil.cc:2204
google::protobuf::compiler::js::GeneratorOptions::import_style
enum google::protobuf::compiler::js::GeneratorOptions::ImportStyle import_style
google::protobuf::FieldDescriptor::name
const std::string & name() const
common.h
google::protobuf::FileDescriptor::message_type
const Descriptor * message_type(int index) const
enum_descriptor
VALUE enum_descriptor(VALUE self)
Definition: ruby/ext/google/protobuf_c/message.c:801
google::protobuf::FileDescriptor::dependency
const FileDescriptor * dependency(int index) const
Definition: src/google/protobuf/descriptor.cc:7271
value_type
zend_class_entry * value_type
Definition: php/ext/google/protobuf/message.c:2546
google::protobuf::FieldDescriptor::TYPE_FIXED64
@ TYPE_FIXED64
Definition: src/google/protobuf/descriptor.h:531
google::protobuf::compiler::js::Generator::GenerateClassConstructorAndDeclareExtensionFieldInfo
void GenerateClassConstructorAndDeclareExtensionFieldInfo(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2102
google::protobuf::FileDescriptor::extension
const FieldDescriptor * extension(int index) const
google::protobuf::compiler::SCC::descriptors
std::vector< const Descriptor * > descriptors
Definition: scc.h:50
google::protobuf::compiler::js::Generator::GenerateRequiresForExtensions
void GenerateRequiresForExtensions(const GeneratorOptions &options, io::Printer *printer, const std::vector< const FieldDescriptor * > &fields, std::set< std::string > *provided) const
Definition: js_generator.cc:1867
stringprintf.h
google::protobuf::Descriptor::name
const std::string & name() const
google::protobuf::compiler::js::Generator::GenerateClassFieldToObject
void GenerateClassFieldToObject(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field) const
Definition: js_generator.cc:2348
logging.h
google::protobuf::Descriptor::file
const FileDescriptor * file() const
google::protobuf::EnumValueDescriptor
Definition: src/google/protobuf/descriptor.h:1075
google::protobuf::compiler::cpp::HasRepeatedFields
static bool HasRepeatedFields(const Descriptor *descriptor)
Definition: cpp_helpers.cc:801
google::protobuf::Descriptor
Definition: src/google/protobuf/descriptor.h:231
descriptor.h
google::protobuf::FieldDescriptor::TYPE_GROUP
@ TYPE_GROUP
Definition: src/google/protobuf/descriptor.h:535
google::protobuf::compiler::ParseGeneratorParameter
void ParseGeneratorParameter(const std::string &text, std::vector< std::pair< std::string, std::string > > *output)
Definition: code_generator.cc:101
google::protobuf::compiler::SCCAnalyzer
Definition: scc.h:63
google::protobuf::FieldDescriptor::TYPE_SFIXED32
@ TYPE_SFIXED32
Definition: src/google/protobuf/descriptor.h:541
google::protobuf::compiler::js::GeneratorOptions::extension
std::string extension
Definition: js_generator.h:125
first
GLint first
Definition: glcorearb.h:2830
google::protobuf::compiler::js::Generator::GenerateClassFromObject
void GenerateClassFromObject(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2451
google::protobuf::compiler::js::Generator::FindProvidesForMessage
void FindProvidesForMessage(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc, std::set< std::string > *provided) const
Definition: js_generator.cc:1717
google::protobuf::FieldDescriptor::message_type
const Descriptor * message_type() const
Definition: src/google/protobuf/descriptor.cc:7228
google::protobuf::FieldDescriptor::TYPE_UINT64
@ TYPE_UINT64
Definition: src/google/protobuf/descriptor.h:527
google::protobuf::compiler::js::Generator::GenerateProvides
void GenerateProvides(const GeneratorOptions &options, io::Printer *printer, std::set< std::string > *provided) const
Definition: js_generator.cc:1763
google::protobuf::FileDescriptor
Definition: src/google/protobuf/descriptor.h:1320
google::protobuf::compiler::js::Generator::GenerateClassExtensionFieldInfo
void GenerateClassExtensionFieldInfo(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:3020
google::protobuf::EnumValueDescriptor::full_name
const std::string & full_name() const
google::protobuf::io::AnnotationProtoCollector
Definition: printer.h:76
google::protobuf::FieldDescriptor::TYPE_INT64
@ TYPE_INT64
Definition: src/google/protobuf/descriptor.h:524
google::protobuf::compiler::js::GeneratorOptions::kImportClosure
@ kImportClosure
Definition: js_generator.h:71
words
std::vector< std::string > words
Definition: repeated_field_unittest.cc:1788
google::protobuf::compiler::cpp::HasFieldPresence
bool HasFieldPresence(const FileDescriptor *file)
Definition: cpp_helpers.h:413
google::protobuf::compiler::js::Generator::FindRequiresForExtension
void FindRequiresForExtension(const GeneratorOptions &options, const FieldDescriptor *field, std::set< std::string > *required, std::set< std::string > *forwards) const
Definition: js_generator.cc:1980
google::protobuf::compiler::js::Generator::GenerateAll
virtual bool GenerateAll(const std::vector< const FileDescriptor * > &files, const std::string &parameter, GeneratorContext *context, std::string *error) const
Definition: js_generator.cc:3720
js_generator.h
google::protobuf::compiler::js::Generator::GenerateClass
void GenerateClass(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2012
google::protobuf::Join
void Join(Iterator start, Iterator end, const char *delim, string *result)
Definition: strutil.h:769
f
GLfloat f
Definition: glcorearb.h:3964
google::protobuf::compiler::js::Generator::GenerateFilesInDepOrder
void GenerateFilesInDepOrder(const GeneratorOptions &options, io::Printer *printer, const std::vector< const FileDescriptor * > &file) const
Definition: js_generator.cc:3574
value
GLsizei const GLfloat * value
Definition: glcorearb.h:3093
google::protobuf::compiler::js::GeneratorOptions::annotate_code
bool annotate_code
Definition: js_generator.h:133
google::protobuf::OneofDescriptor::field_count
int field_count() const
descriptor.pb.h
assert.h
google::protobuf::compiler::js::Generator::GenerateClassRegistration
void GenerateClassRegistration(const GeneratorOptions &options, io::Printer *printer, const Descriptor *desc) const
Definition: js_generator.cc:2537
binary
const GLuint GLenum const GLvoid * binary
Definition: glcorearb.h:3962
google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE
@ CPPTYPE_MESSAGE
Definition: src/google/protobuf/descriptor.h:563
google::protobuf::StripSuffixString
string StripSuffixString(const string &str, const string &suffix)
Definition: strutil.h:143
output
const upb_json_parsermethod const upb_symtab upb_sink * output
Definition: ruby/ext/google/protobuf_c/upb.h:10503
GeneratedCodeInfo
Definition: descriptor.pb.h:6355
google::protobuf::FieldDescriptor::CPPTYPE_INT32
@ CPPTYPE_INT32
Definition: src/google/protobuf/descriptor.h:554
google::protobuf::FieldDescriptor::TYPE_ENUM
@ TYPE_ENUM
Definition: src/google/protobuf/descriptor.h:540
google::protobuf::compiler::js::GeneratorOptions::kImportCommonJsStrict
@ kImportCommonJsStrict
Definition: js_generator.h:73
google::protobuf::EnumDescriptor
Definition: src/google/protobuf/descriptor.h:918
count
GLint GLsizei count
Definition: glcorearb.h:2830
google::protobuf::FieldDescriptor::TYPE_SFIXED64
@ TYPE_SFIXED64
Definition: src/google/protobuf/descriptor.h:542
google::protobuf::StringPiece::size
stringpiece_ssize_type size() const
Definition: stringpiece.h:248
google::protobuf::compiler::GeneratorContext
Definition: code_generator.h:119
index
GLuint index
Definition: glcorearb.h:3055
google::protobuf::compiler::js::GeneratorOptions::error_on_name_conflict
bool error_on_name_conflict
Definition: js_generator.h:123
google::protobuf::FileDescriptor::message_type_count
int message_type_count() const
google::protobuf::OneofDescriptor::containing_type
const Descriptor * containing_type() const
google::protobuf::compiler::js::GeneratorOptions::add_require_for_enums
bool add_require_for_enums
Definition: js_generator.h:116
google::protobuf::compiler::js::GeneratorOptions::kEverythingInOneFile
@ kEverythingInOneFile
Definition: js_generator.h:106
google::protobuf::FieldDescriptor::cpp_type
CppType cpp_type() const
Definition: src/google/protobuf/descriptor.h:2139
it
MapIter it
Definition: php/ext/google/protobuf/map.c:205
compiler
Definition: plugin.pb.cc:22
google
Definition: data_proto2_to_proto3_util.h:11
google::protobuf::FileDescriptor::extension_count
int extension_count() const
google::protobuf::compiler::js::FindProvidesForOneOfEnum
void FindProvidesForOneOfEnum(const GeneratorOptions &options, const OneofDescriptor *oneof, std::set< std::string > *provided)
Definition: js_generator.cc:1696
google::protobuf::compiler::js::Generator::GenerateFieldValueExpression
void GenerateFieldValueExpression(io::Printer *printer, const char *obj_reference, const FieldDescriptor *field, bool use_default) const
Definition: js_generator.cc:2300
google::protobuf::FileDescriptor::dependency_count
int dependency_count() const
google::protobuf::compiler::js::Generator::FindProvidesForEnum
void FindProvidesForEnum(const GeneratorOptions &options, io::Printer *printer, const EnumDescriptor *enumdesc, std::set< std::string > *provided) const
Definition: js_generator.cc:1738
google::protobuf::FieldDescriptor::TYPE_FIXED32
@ TYPE_FIXED32
Definition: src/google/protobuf/descriptor.h:532
google::protobuf::compiler::js::Generator::FindRequiresForField
void FindRequiresForField(const GeneratorOptions &options, const FieldDescriptor *field, std::set< std::string > *required, std::set< std::string > *forwards) const
Definition: js_generator.cc:1960
google::protobuf::compiler::js::Generator::GenerateClassFieldFromObject
void GenerateClassFieldFromObject(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field) const
Definition: js_generator.cc:2482
google::protobuf::compiler::js::Generator::GenerateRepeatedMessageHelperMethods
void GenerateRepeatedMessageHelperMethods(const GeneratorOptions &options, io::Printer *printer, const FieldDescriptor *field) const
Definition: js_generator.cc:2992


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:55