• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 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/enum_field.h"
9 
10 #include <string>
11 
12 #include "absl/container/btree_set.h"
13 #include "absl/container/flat_hash_map.h"
14 #include "absl/container/flat_hash_set.h"
15 #include "absl/strings/str_cat.h"
16 #include "absl/strings/string_view.h"
17 #include "google/protobuf/compiler/objectivec/field.h"
18 #include "google/protobuf/compiler/objectivec/names.h"
19 #include "google/protobuf/compiler/objectivec/options.h"
20 #include "google/protobuf/descriptor.h"
21 #include "google/protobuf/io/printer.h"
22 
23 namespace google {
24 namespace protobuf {
25 namespace compiler {
26 namespace objectivec {
27 
28 namespace {
29 
SetEnumVariables(const FieldDescriptor * descriptor,const GenerationOptions & generation_options,absl::flat_hash_map<absl::string_view,std::string> * variables)30 void SetEnumVariables(
31     const FieldDescriptor* descriptor,
32     const GenerationOptions& generation_options,
33     absl::flat_hash_map<absl::string_view, std::string>* variables) {
34   const std::string type = EnumName(descriptor->enum_type());
35   const std::string enum_desc_func = absl::StrCat(type, "_EnumDescriptor");
36   (*variables)["enum_name"] = type;
37   // When using fwd decls, for non repeated fields, if it was defined in a
38   // different file, the property decls need to use "enum NAME" rather than just
39   // "NAME" to support the forward declaration of the enums.
40   if (generation_options.headers_use_forward_declarations &&
41       !descriptor->is_repeated() &&
42       !IsProtobufLibraryBundledProtoFile(descriptor->enum_type()->file()) &&
43       (descriptor->file() != descriptor->enum_type()->file())) {
44     (*variables)["property_type"] = absl::StrCat("enum ", type, " ");
45   }
46   (*variables)["enum_verifier"] = absl::StrCat(type, "_IsValidValue");
47   (*variables)["enum_desc_func"] = enum_desc_func;
48 
49   (*variables)["dataTypeSpecific_name"] = "enumDescFunc";
50   (*variables)["dataTypeSpecific_value"] = enum_desc_func;
51 
52   const Descriptor* msg_descriptor = descriptor->containing_type();
53   (*variables)["owning_message_class"] = ClassName(msg_descriptor);
54 }
55 }  // namespace
56 
EnumFieldGenerator(const FieldDescriptor * descriptor,const GenerationOptions & generation_options)57 EnumFieldGenerator::EnumFieldGenerator(
58     const FieldDescriptor* descriptor,
59     const GenerationOptions& generation_options)
60     : SingleFieldGenerator(descriptor, generation_options) {
61   SetEnumVariables(descriptor, generation_options, &variables_);
62 }
63 
GenerateCFunctionDeclarations(io::Printer * printer) const64 void EnumFieldGenerator::GenerateCFunctionDeclarations(
65     io::Printer* printer) const {
66   if (descriptor_->enum_type()->is_closed()) {
67     return;
68   }
69 
70   auto vars = printer->WithVars(variables_);
71   printer->Emit(R"objc(
72     /**
73      * Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even
74      * if the value was not defined by the enum at the time the code was generated.
75      **/
76     int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message);
77     /**
78      * Sets the raw value of an @c $owning_message_class$'s @c $name$ property, allowing
79      * it to be set to a value that was not defined by the enum at the time the code
80      * was generated.
81      **/
82     void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);
83   )objc");
84   printer->Emit("\n");
85 }
86 
GenerateCFunctionImplementations(io::Printer * printer) const87 void EnumFieldGenerator::GenerateCFunctionImplementations(
88     io::Printer* printer) const {
89   if (descriptor_->enum_type()->is_closed()) {
90     return;
91   }
92 
93   auto vars = printer->WithVars(variables_);
94   printer->Emit(R"objc(
95     int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {
96       GPBDescriptor *descriptor = [$owning_message_class$ descriptor];
97       GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];
98       return GPBGetMessageRawEnumField(message, field);
99     }
100 
101     void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value) {
102       GPBDescriptor *descriptor = [$owning_message_class$ descriptor];
103       GPBFieldDescriptor *field = [descriptor fieldWithNumber:$field_number_name$];
104       GPBSetMessageRawEnumField(message, field, value);
105     }
106   )objc");
107   printer->Emit("\n");
108 }
109 
DetermineForwardDeclarations(absl::btree_set<std::string> * fwd_decls,bool include_external_types) const110 void EnumFieldGenerator::DetermineForwardDeclarations(
111     absl::btree_set<std::string>* fwd_decls,
112     bool include_external_types) const {
113   SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls,
114                                                      include_external_types);
115   // If it is an enum defined in a different file (and not a WKT), then we'll
116   // need a forward declaration for it.  When it is in our file, all the enums
117   // are output before the message, so it will be declared before it is needed.
118   if (include_external_types &&
119       descriptor_->file() != descriptor_->enum_type()->file() &&
120       !IsProtobufLibraryBundledProtoFile(descriptor_->enum_type()->file())) {
121     const std::string& name = variable("enum_name");
122     fwd_decls->insert(absl::StrCat("GPB_ENUM_FWD_DECLARE(", name, ");"));
123   }
124 }
125 
DetermineNeededFiles(absl::flat_hash_set<const FileDescriptor * > * deps) const126 void EnumFieldGenerator::DetermineNeededFiles(
127     absl::flat_hash_set<const FileDescriptor*>* deps) const {
128   if (descriptor_->file() != descriptor_->enum_type()->file()) {
129     deps->insert(descriptor_->enum_type()->file());
130   }
131 }
132 
RepeatedEnumFieldGenerator(const FieldDescriptor * descriptor,const GenerationOptions & generation_options)133 RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
134     const FieldDescriptor* descriptor,
135     const GenerationOptions& generation_options)
136     : RepeatedFieldGenerator(descriptor, generation_options) {
137   SetEnumVariables(descriptor, generation_options, &variables_);
138 }
139 
EmitArrayComment(io::Printer * printer) const140 void RepeatedEnumFieldGenerator::EmitArrayComment(io::Printer* printer) const {
141   auto vars = printer->WithVars(variables_);
142   printer->Emit(R"objc(
143     // |$name$| contains |$enum_name$|
144   )objc");
145 }
146 
147 // NOTE: RepeatedEnumFieldGenerator::DetermineForwardDeclarations isn't needed
148 // because `GPBEnumArray` isn't generic (like `NSArray` would be for messages)
149 // and thus doesn't reference the type in the header.
150 
DetermineNeededFiles(absl::flat_hash_set<const FileDescriptor * > * deps) const151 void RepeatedEnumFieldGenerator::DetermineNeededFiles(
152     absl::flat_hash_set<const FileDescriptor*>* deps) const {
153   if (descriptor_->file() != descriptor_->enum_type()->file()) {
154     deps->insert(descriptor_->enum_type()->file());
155   }
156 }
157 
158 }  // namespace objectivec
159 }  // namespace compiler
160 }  // namespace protobuf
161 }  // namespace google
162