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