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: kenton@google.com (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 | |
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(s: "EnumTypeTraits< " ); |
61 | type_traits_.append(str: ClassName(descriptor: descriptor_->enum_type(), qualified: true)); |
62 | type_traits_.append(s: ", " ); |
63 | type_traits_.append(str: ClassName(descriptor: descriptor_->enum_type(), qualified: true)); |
64 | type_traits_.append(s: "_IsValid>" ); |
65 | break; |
66 | case FieldDescriptor::CPPTYPE_STRING: |
67 | type_traits_.append(s: "StringTypeTraits" ); |
68 | break; |
69 | case FieldDescriptor::CPPTYPE_MESSAGE: |
70 | type_traits_.append(s: "MessageTypeTraits< " ); |
71 | type_traits_.append(str: ClassName(descriptor: descriptor_->message_type(), qualified: true)); |
72 | type_traits_.append(s: " >" ); |
73 | break; |
74 | default: |
75 | type_traits_.append(s: "PrimitiveTypeTraits< " ); |
76 | type_traits_.append(str: PrimitiveTypeName(options: options_, type: descriptor_->cpp_type())); |
77 | type_traits_.append(s: " >" ); |
78 | break; |
79 | } |
80 | SetCommonVars(options, variables: &variables_); |
81 | SetCommonMessageDataVariables(descriptor: descriptor_->containing_type(), variables: &variables_); |
82 | variables_["extendee" ] = |
83 | QualifiedClassName(d: descriptor_->containing_type(), options: options_); |
84 | variables_["type_traits" ] = type_traits_; |
85 | std::string name = descriptor_->name(); |
86 | variables_["name" ] = ResolveKeyword(name); |
87 | variables_["constant_name" ] = FieldConstantName(field: descriptor_); |
88 | variables_["field_type" ] = |
89 | StrCat(a: static_cast<int>(descriptor_->type())); |
90 | variables_["packed" ] = descriptor_->is_packed() ? "true" : "false" ; |
91 | |
92 | std::string scope = |
93 | IsScoped() ? ClassName(descriptor: descriptor_->extension_scope(), qualified: false) + "::" : "" ; |
94 | variables_["scope" ] = scope; |
95 | variables_["scoped_name" ] = ExtensionName(d: descriptor_); |
96 | variables_["number" ] = StrCat(a: 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: descriptor_->message_type(), options: options_, scc_analyzer: scc_analyzer_) && |
103 | ShouldVerify(descriptor: descriptor_->containing_type(), options: options_, scc_analyzer: scc_analyzer_); |
104 | |
105 | variables_["verify_fn" ] = |
106 | add_verify_fn |
107 | ? StrCat(a: "&" , b: FieldMessageTypeName(field: descriptor_, options: options_), |
108 | c: "::InternalVerify" ) |
109 | : "nullptr" ; |
110 | } |
111 | |
112 | ExtensionGenerator::~ExtensionGenerator() {} |
113 | |
114 | bool ExtensionGenerator::IsScoped() const { |
115 | return descriptor_->extension_scope() != nullptr; |
116 | } |
117 | |
118 | 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 | |
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(s: variables_["scoped_name" ], oldsub: "::" , newsub: "_" , replace_all: true) + "_default" ; |
163 | format("const std::string $1$($2$);\n" , default_str, |
164 | DefaultValue(options: options_, field: 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(field: descriptor_, options: options_) + "::default_instance()" ; |
170 | } else { |
171 | default_str = DefaultValue(options: options_, field: 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 | |