xref: /aosp_15_r20/external/cronet/third_party/protobuf/src/google/protobuf/compiler/cpp/extension.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 
31 // Author: [email protected] (Kenton Varda)
32 //  Based on original Protocol Buffers design by
33 //  Sanjay Ghemawat, Jeff Dean, and others.
34 
35 #include <google/protobuf/compiler/cpp/extension.h>
36 
37 #include <map>
38 
39 #include <google/protobuf/io/printer.h>
40 #include <google/protobuf/stubs/strutil.h>
41 #include <google/protobuf/compiler/cpp/helpers.h>
42 #include <google/protobuf/descriptor.pb.h>
43 
44 namespace google {
45 namespace protobuf {
46 namespace compiler {
47 namespace cpp {
48 
ExtensionGenerator(const FieldDescriptor * descriptor,const Options & options,MessageSCCAnalyzer * scc_analyzer)49 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
50                                        const Options& options,
51                                        MessageSCCAnalyzer* scc_analyzer)
52     : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) {
53   // Construct type_traits_.
54   if (descriptor_->is_repeated()) {
55     type_traits_ = "Repeated";
56   }
57 
58   switch (descriptor_->cpp_type()) {
59     case FieldDescriptor::CPPTYPE_ENUM:
60       type_traits_.append("EnumTypeTraits< ");
61       type_traits_.append(ClassName(descriptor_->enum_type(), true));
62       type_traits_.append(", ");
63       type_traits_.append(ClassName(descriptor_->enum_type(), true));
64       type_traits_.append("_IsValid>");
65       break;
66     case FieldDescriptor::CPPTYPE_STRING:
67       type_traits_.append("StringTypeTraits");
68       break;
69     case FieldDescriptor::CPPTYPE_MESSAGE:
70       type_traits_.append("MessageTypeTraits< ");
71       type_traits_.append(ClassName(descriptor_->message_type(), true));
72       type_traits_.append(" >");
73       break;
74     default:
75       type_traits_.append("PrimitiveTypeTraits< ");
76       type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type()));
77       type_traits_.append(" >");
78       break;
79   }
80   SetCommonVars(options, &variables_);
81   SetCommonMessageDataVariables(descriptor_->containing_type(), &variables_);
82   variables_["extendee"] =
83       QualifiedClassName(descriptor_->containing_type(), options_);
84   variables_["type_traits"] = type_traits_;
85   std::string name = descriptor_->name();
86   variables_["name"] = ResolveKeyword(name);
87   variables_["constant_name"] = FieldConstantName(descriptor_);
88   variables_["field_type"] =
89       StrCat(static_cast<int>(descriptor_->type()));
90   variables_["packed"] = descriptor_->is_packed() ? "true" : "false";
91 
92   std::string scope =
93       IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : "";
94   variables_["scope"] = scope;
95   variables_["scoped_name"] = ExtensionName(descriptor_);
96   variables_["number"] = StrCat(descriptor_->number());
97 
98   bool add_verify_fn =
99       // Only verify msgs.
100       descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
101       // Options say to verify.
102       ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
103       ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_);
104 
105   variables_["verify_fn"] =
106       add_verify_fn
107           ? StrCat("&", FieldMessageTypeName(descriptor_, options_),
108                          "::InternalVerify")
109           : "nullptr";
110 }
111 
~ExtensionGenerator()112 ExtensionGenerator::~ExtensionGenerator() {}
113 
IsScoped() const114 bool ExtensionGenerator::IsScoped() const {
115   return descriptor_->extension_scope() != nullptr;
116 }
117 
GenerateDeclaration(io::Printer * printer) const118 void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const {
119   Formatter format(printer, variables_);
120 
121   // If this is a class member, it needs to be declared "static".  Otherwise,
122   // it needs to be "extern".  In the latter case, it also needs the DLL
123   // export/import specifier.
124   std::string qualifier;
125   if (!IsScoped()) {
126     qualifier = "extern";
127     if (!options_.dllexport_decl.empty()) {
128       qualifier = options_.dllexport_decl + " " + qualifier;
129     }
130   } else {
131     qualifier = "static";
132   }
133 
134   format(
135       "static const int $constant_name$ = $number$;\n"
136       "$1$ ::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
137       "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
138       "  ${2$$name$$}$;\n",
139       qualifier, descriptor_);
140 }
141 
GenerateDefinition(io::Printer * printer)142 void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
143   // If we are building for lite with implicit weak fields, we want to skip over
144   // any custom options (i.e. extensions of messages from descriptor.proto).
145   // This prevents the creation of any unnecessary linker references to the
146   // descriptor messages.
147   if (options_.lite_implicit_weak_fields &&
148       descriptor_->containing_type()->file()->name() ==
149           "net/proto2/proto/descriptor.proto") {
150     return;
151   }
152 
153   Formatter format(printer, variables_);
154   std::string default_str;
155   // If this is a class member, it needs to be declared in its class scope.
156   if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
157     // We need to declare a global string which will contain the default value.
158     // We cannot declare it at class scope because that would require exposing
159     // it in the header which would be annoying for other reasons.  So we
160     // replace :: with _ in the name and declare it as a global.
161     default_str =
162         StringReplace(variables_["scoped_name"], "::", "_", true) + "_default";
163     format("const std::string $1$($2$);\n", default_str,
164            DefaultValue(options_, descriptor_));
165   } else if (descriptor_->message_type()) {
166     // We have to initialize the default instance for extensions at registration
167     // time.
168     default_str =
169         FieldMessageTypeName(descriptor_, options_) + "::default_instance()";
170   } else {
171     default_str = DefaultValue(options_, descriptor_);
172   }
173 
174   // Likewise, class members need to declare the field constant variable.
175   if (IsScoped()) {
176     format(
177         "#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)\n"
178         "const int $scope$$constant_name$;\n"
179         "#endif\n");
180   }
181 
182   format(
183       "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 "
184       "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
185       "    ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$>\n"
186       "  $scoped_name$($constant_name$, $1$, $verify_fn$);\n",
187       default_str);
188 }
189 
190 }  // namespace cpp
191 }  // namespace compiler
192 }  // namespace protobuf
193 }  // namespace google
194