• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2015 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "google/protobuf/compiler/objectivec/map_field.h"
9 
10 #include <string>
11 #include <vector>
12 
13 #include "absl/container/btree_set.h"
14 #include "absl/container/flat_hash_set.h"
15 #include "absl/strings/match.h"
16 #include "absl/strings/str_cat.h"
17 #include "google/protobuf/compiler/objectivec/field.h"
18 #include "google/protobuf/compiler/objectivec/helpers.h"
19 #include "google/protobuf/compiler/objectivec/names.h"
20 #include "google/protobuf/compiler/objectivec/options.h"
21 #include "google/protobuf/descriptor.h"
22 
23 namespace google {
24 namespace protobuf {
25 namespace compiler {
26 namespace objectivec {
27 
28 // MapFieldGenerator uses RepeatedFieldGenerator as the parent because it
29 // provides a bunch of things (no has* methods, comments for contained type,
30 // etc.).
31 
MapFieldGenerator(const FieldDescriptor * descriptor,const GenerationOptions & generation_options)32 MapFieldGenerator::MapFieldGenerator(
33     const FieldDescriptor* descriptor,
34     const GenerationOptions& generation_options)
35     : RepeatedFieldGenerator(descriptor, generation_options) {
36   const FieldDescriptor* key_descriptor = descriptor->message_type()->map_key();
37   const FieldDescriptor* value_descriptor =
38       descriptor->message_type()->map_value();
39   value_field_generator_.reset(
40       FieldGenerator::Make(value_descriptor, generation_options));
41 
42   // Pull over some variables_ from the value.
43   variables_["field_type"] = value_field_generator_->variable("field_type");
44   variables_["default"] = value_field_generator_->variable("default");
45   variables_["default_name"] = value_field_generator_->variable("default_name");
46 
47   // Build custom field flags.
48   std::vector<std::string> field_flags;
49   field_flags.push_back(
50       absl::StrCat("GPBFieldMapKey", GetCapitalizedType(key_descriptor)));
51   // Pull over the current text format custom name values that was calculated.
52   if (absl::StrContains(variables_["fieldflags"],
53                         "GPBFieldTextFormatNameCustom")) {
54     field_flags.push_back("GPBFieldTextFormatNameCustom");
55   }
56   // Pull over some info from the value's flags.
57   const std::string& value_field_flags =
58       value_field_generator_->variable("fieldflags");
59   if (absl::StrContains(value_field_flags, "GPBFieldHasDefaultValue")) {
60     field_flags.push_back("GPBFieldHasDefaultValue");
61   }
62   if (absl::StrContains(value_field_flags, "GPBFieldHasEnumDescriptor")) {
63     field_flags.push_back("GPBFieldHasEnumDescriptor");
64     if (absl::StrContains(value_field_flags, "GPBFieldClosedEnum")) {
65       field_flags.push_back("GPBFieldClosedEnum");
66     }
67   }
68 
69   variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
70 
71   variables_["dataTypeSpecific_name"] =
72       value_field_generator_->variable("dataTypeSpecific_name");
73   variables_["dataTypeSpecific_value"] =
74       value_field_generator_->variable("dataTypeSpecific_value");
75 }
76 
EmitArrayComment(io::Printer * printer) const77 void MapFieldGenerator::EmitArrayComment(io::Printer* printer) const {
78   // Use the array_comment support in RepeatedFieldGenerator to output what the
79   // values in the map are.
80   const FieldDescriptor* value_descriptor =
81       descriptor_->message_type()->map_value();
82   if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) {
83     printer->Emit(
84         {{"name", variable("name")},
85          {"enum_name", value_field_generator_->variable("enum_name")}},
86         R"objc(
87           // |$name$| values are |$enum_name$|
88         )objc");
89   }
90 }
91 
DetermineForwardDeclarations(absl::btree_set<std::string> * fwd_decls,bool include_external_types) const92 void MapFieldGenerator::DetermineForwardDeclarations(
93     absl::btree_set<std::string>* fwd_decls,
94     bool include_external_types) const {
95   RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls,
96                                                        include_external_types);
97   const FieldDescriptor* value_descriptor =
98       descriptor_->message_type()->map_value();
99   // NOTE: Maps with values of enums don't have to worry about adding the
100   // forward declaration because `GPB*EnumDictionary` isn't generic to the
101   // specific enum (like say `NSDictionary<String, MyMessage>`) and thus doesn't
102   // reference the type in the header.
103   if (GetObjectiveCType(value_descriptor) != OBJECTIVECTYPE_MESSAGE) {
104     return;
105   }
106 
107   const Descriptor* value_msg_descriptor = value_descriptor->message_type();
108 
109   // Within a file there is no requirement on the order of the messages, so
110   // local references need a forward declaration. External files (not WKTs),
111   // need one when requested.
112   if ((include_external_types &&
113        !IsProtobufLibraryBundledProtoFile(value_msg_descriptor->file())) ||
114       descriptor_->file() == value_msg_descriptor->file()) {
115     const std::string& value_type =
116         value_field_generator_->variable("msg_type");
117     fwd_decls->insert(absl::StrCat("@class ", value_type, ";"));
118   }
119 }
120 
DetermineObjectiveCClassDefinitions(absl::btree_set<std::string> * fwd_decls) const121 void MapFieldGenerator::DetermineObjectiveCClassDefinitions(
122     absl::btree_set<std::string>* fwd_decls) const {
123   // Class name is already in value's "msg_type".
124   const FieldDescriptor* value_descriptor =
125       descriptor_->message_type()->map_value();
126   if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) {
127     fwd_decls->insert(
128         ObjCClassDeclaration(value_field_generator_->variable("msg_type")));
129   }
130 }
131 
DetermineNeededFiles(absl::flat_hash_set<const FileDescriptor * > * deps) const132 void MapFieldGenerator::DetermineNeededFiles(
133     absl::flat_hash_set<const FileDescriptor*>* deps) const {
134   const FieldDescriptor* value_descriptor =
135       descriptor_->message_type()->map_value();
136   const ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
137   if (value_objc_type == OBJECTIVECTYPE_MESSAGE) {
138     const Descriptor* value_msg_descriptor = value_descriptor->message_type();
139     if (descriptor_->file() != value_msg_descriptor->file()) {
140       deps->insert(value_msg_descriptor->file());
141     }
142   } else if (value_objc_type == OBJECTIVECTYPE_ENUM) {
143     const EnumDescriptor* value_enum_descriptor = value_descriptor->enum_type();
144     if (descriptor_->file() != value_enum_descriptor->file()) {
145       deps->insert(value_enum_descriptor->file());
146     }
147   }
148 }
149 
150 }  // namespace objectivec
151 }  // namespace compiler
152 }  // namespace protobuf
153 }  // namespace google
154