• 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 // Author: kenton@google.com (Kenton Varda)
9 //  Based on original Protocol Buffers design by
10 //  Sanjay Ghemawat, Jeff Dean, and others.
11 
12 #include "google/protobuf/compiler/cpp/extension.h"
13 
14 #include <string>
15 #include <vector>
16 
17 #include "absl/log/absl_check.h"
18 #include "absl/strings/str_cat.h"
19 #include "absl/strings/str_replace.h"
20 #include "google/protobuf/compiler/cpp/helpers.h"
21 #include "google/protobuf/compiler/cpp/options.h"
22 #include "google/protobuf/descriptor.h"
23 #include "google/protobuf/descriptor.pb.h"
24 #include "google/protobuf/io/printer.h"
25 
26 namespace google {
27 namespace protobuf {
28 namespace compiler {
29 namespace cpp {
30 
ExtensionGenerator(const FieldDescriptor * descriptor,const Options & options,MessageSCCAnalyzer * scc_analyzer)31 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
32                                        const Options& options,
33                                        MessageSCCAnalyzer* scc_analyzer)
34     : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) {
35   // Construct type_traits_.
36   if (descriptor_->is_repeated()) {
37     type_traits_ = "Repeated";
38   }
39 
40   switch (descriptor_->cpp_type()) {
41     case FieldDescriptor::CPPTYPE_ENUM:
42       type_traits_.append("EnumTypeTraits< ");
43       type_traits_.append(ClassName(descriptor_->enum_type(), true));
44       type_traits_.append(", ");
45       type_traits_.append(ClassName(descriptor_->enum_type(), true));
46       type_traits_.append("_IsValid>");
47       break;
48     case FieldDescriptor::CPPTYPE_STRING:
49       type_traits_.append("StringTypeTraits");
50       break;
51     case FieldDescriptor::CPPTYPE_MESSAGE:
52       type_traits_.append("MessageTypeTraits< ");
53       type_traits_.append(ClassName(descriptor_->message_type(), true));
54       type_traits_.append(" >");
55       break;
56     default:
57       type_traits_.append("PrimitiveTypeTraits< ");
58       type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type()));
59       type_traits_.append(" >");
60       break;
61   }
62   SetCommonMessageDataVariables(descriptor_->containing_type(), &variables_);
63   variables_["extendee"] =
64       QualifiedClassName(descriptor_->containing_type(), options_);
65   variables_["type_traits"] = type_traits_;
66   variables_["name"] = ResolveKeyword(descriptor_->name());
67   variables_["constant_name"] = FieldConstantName(descriptor_);
68   variables_["field_type"] =
69       absl::StrCat(static_cast<int>(descriptor_->type()));
70   variables_["repeated"] = descriptor_->is_repeated() ? "true" : "false";
71   variables_["packed"] = descriptor_->is_packed() ? "true" : "false";
72   variables_["dllexport_decl"] = options.dllexport_decl;
73 
74   std::string scope;
75   if (IsScoped()) {
76     scope =
77         absl::StrCat(ClassName(descriptor_->extension_scope(), false), "::");
78   }
79 
80   variables_["scope"] = scope;
81   variables_["scoped_name"] = ExtensionName(descriptor_);
82   variables_["number"] = absl::StrCat(descriptor_->number());
83 }
84 
85 ExtensionGenerator::~ExtensionGenerator() = default;
86 
IsScoped() const87 bool ExtensionGenerator::IsScoped() const {
88   return descriptor_->extension_scope() != nullptr;
89 }
90 
GenerateDeclaration(io::Printer * p) const91 void ExtensionGenerator::GenerateDeclaration(io::Printer* p) const {
92   auto var = p->WithVars(variables_);
93   auto annotate = p->WithAnnotations({{"name", descriptor_}});
94 
95   p->Emit({{"qualifier",
96             // If this is a class member, it needs to be declared "static".
97             // Otherwise, it needs to be "extern".  In the latter case, it
98             // also needs the DLL export/import specifier.
99             IsScoped() ? "static"
100             : options_.dllexport_decl.empty()
101                 ? "extern"
102                 : absl::StrCat(options_.dllexport_decl, " extern")}},
103           R"cc(
104             static const int $constant_name$ = $number$;
105             $qualifier$ ::$proto_ns$::internal::ExtensionIdentifier<
106                 $extendee$, ::$proto_ns$::internal::$type_traits$, $field_type$,
107                 $packed$>
108                 $name$;
109           )cc");
110 }
111 
GenerateDefinition(io::Printer * p)112 void ExtensionGenerator::GenerateDefinition(io::Printer* p) {
113   auto vars = p->WithVars(variables_);
114   auto generate_default_string = [&] {
115     if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
116       // We need to declare a global string which will contain the default
117       // value. We cannot declare it at class scope because that would require
118       // exposing it in the header which would be annoying for other reasons. So
119       // we replace :: with _ in the name and declare it as a global.
120       return absl::StrReplaceAll(variables_["scoped_name"], {{"::", "_"}}) +
121              "_default";
122     } else if (descriptor_->message_type()) {
123       // We have to initialize the default instance for extensions at
124       // registration time.
125       return absl::StrCat("&", QualifiedDefaultInstanceName(
126                                    descriptor_->message_type(), options_));
127     } else {
128       return DefaultValue(options_, descriptor_);
129     }
130   };
131 
132   auto local_var = p->WithVars({
133       {"default_str", generate_default_string()},
134       {"default_val", DefaultValue(options_, descriptor_)},
135       {"message_type", descriptor_->message_type() != nullptr
136                            ? FieldMessageTypeName(descriptor_, options_)
137                            : ""},
138   });
139   p->Emit(
140       {
141           {"declare_default_str",
142            [&] {
143              if (descriptor_->cpp_type() != FieldDescriptor::CPPTYPE_STRING)
144                return;
145 
146              // If this is a class member, it needs to be declared in its class
147              // scope.
148              p->Emit(R"cc(
149                const std::string $default_str$($default_val$);
150              )cc");
151            }},
152           {"declare_const_var",
153            [&] {
154              if (!IsScoped()) return;
155              // Likewise, class members need to declare the field constant
156              // variable.
157              p->Emit(R"cc(
158 #if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
159                const int $scope$$constant_name$;
160 #endif
161              )cc");
162            }},
163           {"define_extension_id",
164            [&] {
165              p->Emit(R"cc(
166                PROTOBUF_CONSTINIT$ dllexport_decl$
167                    PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 ::_pbi::
168                        ExtensionIdentifier<$extendee$, ::_pbi::$type_traits$,
169                                            $field_type$, $packed$>
170                            $scoped_name$($constant_name$, $default_str$);
171              )cc");
172            }},
173       },
174       R"cc(
175         $declare_default_str$;
176         $declare_const_var$;
177         $define_extension_id$;
178       )cc");
179 }
180 
WillGenerateRegistration(InitPriority priority)181 bool ExtensionGenerator::WillGenerateRegistration(InitPriority priority) {
182   // When not using weak descriptors we initialize everything on priority 102.
183   if (!UsingImplicitWeakDescriptor(descriptor_->file(), options_)) {
184     return priority == kInitPriority102;
185   }
186   return true;
187 }
188 
GenerateRegistration(io::Printer * p,InitPriority priority)189 void ExtensionGenerator::GenerateRegistration(io::Printer* p,
190                                               InitPriority priority) {
191   ABSL_CHECK(WillGenerateRegistration(priority));
192   const bool using_implicit_weak_descriptors =
193       UsingImplicitWeakDescriptor(descriptor_->file(), options_);
194   const auto find_index = [](auto* desc) {
195     const std::vector<const Descriptor*> msgs =
196         FlattenMessagesInFile(desc->file());
197     return absl::c_find(msgs, desc) - msgs.begin();
198   };
199   auto vars = p->WithVars(variables_);
200   auto vars2 = p->WithVars({{
201       {"extendee_table",
202        DescriptorTableName(descriptor_->containing_type()->file(), options_)},
203       {"extendee_index", find_index(descriptor_->containing_type())},
204       {"preregister", priority == kInitPriority101},
205   }});
206   switch (descriptor_->cpp_type()) {
207     case FieldDescriptor::CPPTYPE_ENUM:
208       if (using_implicit_weak_descriptors) {
209         p->Emit({{"enum_name", ClassName(descriptor_->enum_type(), true)}},
210                 R"cc(
211                   (::_pbi::ExtensionSet::ShouldRegisterAtThisTime(
212                        {{&$extendee_table$, $extendee_index$}}, $preregister$)
213                        ? ::_pbi::ExtensionSet::RegisterEnumExtension(
214                              ::_pbi::GetPrototypeForWeakDescriptor(
215                                  &$extendee_table$, $extendee_index$, true),
216                              $number$, $field_type$, $repeated$, $packed$,
217                              $enum_name$_IsValid)
218                        : (void)0),
219                 )cc");
220       } else if (priority == kInitPriority102) {
221         p->Emit({{"enum_name", ClassName(descriptor_->enum_type(), true)}},
222                 R"cc(
223                   ::_pbi::ExtensionSet::RegisterEnumExtension(
224                       &$extendee$::default_instance(), $number$, $field_type$,
225                       $repeated$, $packed$, $enum_name$_IsValid),
226                 )cc");
227       }
228 
229       break;
230     case FieldDescriptor::CPPTYPE_MESSAGE: {
231       const bool should_verify =
232           // Only verify msgs.
233           descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
234           // Options say to verify.
235           ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
236           ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_);
237       const auto message_type = FieldMessageTypeName(descriptor_, options_);
238       auto v = p->WithVars(
239           {{"verify", should_verify
240                           ? absl::StrCat("&", message_type, "::InternalVerify")
241                           : "nullptr"},
242            {"message_type", message_type},
243            {"lazy", descriptor_->options().has_lazy()
244                         ? descriptor_->options().lazy() ? "kLazy" : "kEager"
245                         : "kUndefined"}});
246       if (using_implicit_weak_descriptors) {
247         p->Emit(
248             {
249                 {"extension_table",
250                  DescriptorTableName(descriptor_->message_type()->file(),
251                                      options_)},
252                 {"extension_index", find_index(descriptor_->message_type())},
253             },
254             R"cc(
255               (::_pbi::ExtensionSet::ShouldRegisterAtThisTime(
256                    {{&$extendee_table$, $extendee_index$},
257                     {&$extension_table$, $extension_index$}},
258                    $preregister$)
259                    ? ::_pbi::ExtensionSet::RegisterMessageExtension(
260                          ::_pbi::GetPrototypeForWeakDescriptor(
261                              &$extendee_table$, $extendee_index$, true),
262                          $number$, $field_type$, $repeated$, $packed$,
263                          ::_pbi::GetPrototypeForWeakDescriptor(
264                              &$extension_table$, $extension_index$, true),
265                          $verify$, ::_pbi::LazyAnnotation::$lazy$)
266                    : (void)0),
267             )cc");
268       } else if (priority == kInitPriority102) {
269         p->Emit(R"cc(
270           ::_pbi::ExtensionSet::RegisterMessageExtension(
271               &$extendee$::default_instance(), $number$, $field_type$,
272               $repeated$, $packed$, &$message_type$::default_instance(),
273               $verify$, ::_pbi::LazyAnnotation::$lazy$),
274         )cc");
275       }
276       break;
277     }
278 
279     default:
280       if (using_implicit_weak_descriptors) {
281         p->Emit(R"cc(
282           (::_pbi::ExtensionSet::ShouldRegisterAtThisTime(
283                {{&$extendee_table$, $extendee_index$}}, $preregister$)
284                ? ::_pbi::ExtensionSet::RegisterExtension(
285                      ::_pbi::GetPrototypeForWeakDescriptor(&$extendee_table$,
286                                                            $extendee_index$,
287                                                            true),
288                      $number$, $field_type$, $repeated$, $packed$)
289                : (void)0),
290         )cc");
291       } else if (priority == kInitPriority102) {
292         p->Emit(
293             R"cc(
294               ::_pbi::ExtensionSet::RegisterExtension(
295                   &$extendee$::default_instance(), $number$, $field_type$,
296                   $repeated$, $packed$),
297             )cc");
298       }
299 
300       break;
301   }
302 }
303 
304 }  // namespace cpp
305 }  // namespace compiler
306 }  // namespace protobuf
307 }  // namespace google
308