• 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/field.h"
13 
14 #include <cstddef>
15 #include <cstdint>
16 #include <memory>
17 #include <string>
18 #include <vector>
19 
20 #include "absl/base/attributes.h"
21 #include "absl/log/absl_check.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_format.h"
24 #include "absl/strings/string_view.h"
25 #include "absl/types/optional.h"
26 #include "absl/types/span.h"
27 #include "google/protobuf/compiler/cpp/field_generators/generators.h"
28 #include "google/protobuf/compiler/cpp/generator.h"
29 #include "google/protobuf/compiler/cpp/helpers.h"
30 #include "google/protobuf/compiler/cpp/options.h"
31 #include "google/protobuf/compiler/cpp/tracker.h"
32 #include "google/protobuf/cpp_features.pb.h"
33 #include "google/protobuf/descriptor.h"
34 #include "google/protobuf/descriptor.pb.h"
35 #include "google/protobuf/io/printer.h"
36 #include "google/protobuf/wire_format.h"
37 
38 namespace google {
39 namespace protobuf {
40 namespace compiler {
41 namespace cpp {
42 using ::google::protobuf::internal::WireFormat;
43 using Sub = ::google::protobuf::io::Printer::Sub;
44 
FieldVars(const FieldDescriptor * field,const Options & opts)45 std::vector<Sub> FieldVars(const FieldDescriptor* field, const Options& opts) {
46   bool split = ShouldSplit(field, opts);
47   std::vector<Sub> vars = {
48       // This will eventually be renamed to "field", once the existing "field"
49       // variable is replaced with "field_" everywhere.
50       {"name", FieldName(field)},
51       // Same as above, but represents internal use.
52       {"name_internal", FieldName(field)},
53 
54       {"index", field->index()},
55       {"number", field->number()},
56       {"pkg.Msg.field", field->full_name()},
57 
58       {"field_", FieldMemberName(field, split)},
59       {"DeclaredType", DeclaredTypeMethodName(field->type())},
60       {"kTagBytes", WireFormat::TagSize(field->number(), field->type())},
61       Sub("PrepareSplitMessageForWrite",
62           split ? "PrepareSplitMessageForWrite();" : "")
63           .WithSuffix(";"),
64       Sub("DEPRECATED", DeprecatedAttribute(opts, field)).WithSuffix(" "),
65 
66       // These variables are placeholders to pick out the beginning and ends of
67       // identifiers for annotations (when doing so with existing variables
68       // would be ambiguous or impossible). They should never be set to anything
69       // but the empty string.
70       {"{", ""},
71       {"}", ""},
72 
73       // For TSan validation.
74       {"TsanDetectConcurrentMutation",
75        absl::StrCat("::", ProtobufNamespace(opts),
76                     "::internal::TSanWrite(&_impl_)")},
77       {"TsanDetectConcurrentRead",
78        absl::StrCat("::", ProtobufNamespace(opts),
79                     "::internal::TSanRead(&_impl_)")},
80 
81       // Old-style names.
82       {"field", FieldMemberName(field, split)},
83       {"declared_type", DeclaredTypeMethodName(field->type())},
84       {"classname", ClassName(FieldScope(field), false)},
85       {"ns", Namespace(field, opts)},
86       {"tag_size", WireFormat::TagSize(field->number(), field->type())},
87       {"deprecated_attr", DeprecatedAttribute(opts, field)},
88       Sub("WeakDescriptorSelfPin",
89           UsingImplicitWeakDescriptor(field->file(), opts)
90               ? absl::StrCat(
91                     StrongReferenceToType(field->containing_type(), opts), ";")
92               : "")
93           .WithSuffix(";"),
94   };
95 
96   if (const auto* oneof = field->containing_oneof()) {
97     auto field_name = UnderscoresToCamelCase(field->name(), true);
98 
99     vars.push_back({"oneof_name", oneof->name()});
100     vars.push_back({"field_name", field_name});
101     vars.push_back({"oneof_index", oneof->index()});
102     vars.push_back({"has_field", absl::StrFormat("%s_case() == k%s",
103                                                  oneof->name(), field_name)});
104     vars.push_back(
105         {"not_has_field",
106          absl::StrFormat("%s_case() != k%s", oneof->name(), field_name)});
107   }
108 
109   return vars;
110 }
111 
FieldGeneratorBase(const FieldDescriptor * field,const Options & options,MessageSCCAnalyzer * scc)112 FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* field,
113                                        const Options& options,
114                                        MessageSCCAnalyzer* scc)
115     : field_(field), options_(options) {
116   bool is_repeated_or_map = field->is_repeated();
117   should_split_ = ShouldSplit(field, options);
118   is_oneof_ = field->real_containing_oneof() != nullptr;
119   switch (field->cpp_type()) {
120     case FieldDescriptor::CPPTYPE_ENUM:
121     case FieldDescriptor::CPPTYPE_INT32:
122     case FieldDescriptor::CPPTYPE_INT64:
123     case FieldDescriptor::CPPTYPE_UINT32:
124     case FieldDescriptor::CPPTYPE_UINT64:
125     case FieldDescriptor::CPPTYPE_FLOAT:
126     case FieldDescriptor::CPPTYPE_DOUBLE:
127     case FieldDescriptor::CPPTYPE_BOOL:
128       is_trivial_ = has_trivial_value_ = !is_repeated_or_map;
129       has_default_constexpr_constructor_ = is_repeated_or_map;
130       break;
131     case FieldDescriptor::CPPTYPE_STRING:
132       is_string_ = true;
133       is_inlined_ = IsStringInlined(field, options);
134       is_bytes_ = field->type() == FieldDescriptor::TYPE_BYTES;
135       has_default_constexpr_constructor_ = is_repeated_or_map;
136       break;
137     case FieldDescriptor::CPPTYPE_MESSAGE:
138       is_message_ = true;
139       is_group_ = field->type() == FieldDescriptor::TYPE_GROUP;
140       is_foreign_ = IsCrossFileMessage(field);
141       is_weak_ = IsImplicitWeakField(field, options, scc);
142       is_lazy_ = IsLazy(field, options, scc);
143       has_trivial_value_ = !(is_repeated_or_map || is_lazy_);
144       has_default_constexpr_constructor_ = is_repeated_or_map || is_lazy_;
145       break;
146   }
147 
148   has_trivial_zero_default_ = CanInitializeByZeroing(field, options, scc);
149   has_brace_default_assign_ = has_trivial_zero_default_ && !is_lazy_;
150 }
151 
GenerateMemberConstexprConstructor(io::Printer * p) const152 void FieldGeneratorBase::GenerateMemberConstexprConstructor(
153     io::Printer* p) const {
154   ABSL_CHECK(!field_->is_extension());
155   if (field_->is_repeated()) {
156     p->Emit("$name$_{}");
157   } else {
158     p->Emit({{"default", DefaultValue(options_, field_)}},
159             "$name$_{$default$}");
160   }
161 }
162 
GenerateMemberConstructor(io::Printer * p) const163 void FieldGeneratorBase::GenerateMemberConstructor(io::Printer* p) const {
164   ABSL_CHECK(!field_->is_extension());
165   if (field_->is_map()) {
166     p->Emit("$name$_{visibility, arena}");
167   } else if (field_->is_repeated()) {
168     if (ShouldSplit(field_, options_)) {
169       p->Emit("$name$_{}");  // RawPtr<Repeated>
170     } else {
171       p->Emit("$name$_{visibility, arena}");
172     }
173   } else {
174     p->Emit({{"default", DefaultValue(options_, field_)}},
175             "$name$_{$default$}");
176   }
177 }
178 
GenerateMemberCopyConstructor(io::Printer * p) const179 void FieldGeneratorBase::GenerateMemberCopyConstructor(io::Printer* p) const {
180   ABSL_CHECK(!field_->is_extension());
181   if (field_->is_repeated()) {
182     p->Emit("$name$_{visibility, arena, from.$name$_}");
183   } else {
184     p->Emit("$name$_{from.$name$_}");
185   }
186 }
187 
GenerateOneofCopyConstruct(io::Printer * p) const188 void FieldGeneratorBase::GenerateOneofCopyConstruct(io::Printer* p) const {
189   ABSL_CHECK(!field_->is_extension()) << "Not supported";
190   ABSL_CHECK(!field_->is_repeated()) << "Not supported";
191   ABSL_CHECK(!field_->is_map()) << "Not supported";
192   p->Emit("$field$ = from.$field$;\n");
193 }
194 
GenerateAggregateInitializer(io::Printer * p) const195 void FieldGeneratorBase::GenerateAggregateInitializer(io::Printer* p) const {
196   if (ShouldSplit(field_, options_)) {
197     p->Emit(R"cc(
198       decltype(Impl_::Split::$name$_){arena},
199     )cc");
200   } else {
201     p->Emit(R"cc(
202       decltype($field$){arena},
203     )cc");
204   }
205 }
206 
GenerateConstexprAggregateInitializer(io::Printer * p) const207 void FieldGeneratorBase::GenerateConstexprAggregateInitializer(
208     io::Printer* p) const {
209   p->Emit(R"cc(
210     /*decltype($field$)*/ {},
211   )cc");
212 }
213 
GenerateCopyAggregateInitializer(io::Printer * p) const214 void FieldGeneratorBase::GenerateCopyAggregateInitializer(
215     io::Printer* p) const {
216   p->Emit(R"cc(
217     decltype($field$){from.$field$},
218   )cc");
219 }
220 
GenerateCopyConstructorCode(io::Printer * p) const221 void FieldGeneratorBase::GenerateCopyConstructorCode(io::Printer* p) const {
222   if (should_split()) {
223     // There is no copy constructor for the `Split` struct, so we need to copy
224     // the value here.
225     Formatter format(p, variables_);
226     format("$field$ = from.$field$;\n");
227   }
228 }
229 
230 namespace {
MakeGenerator(const FieldDescriptor * field,const Options & options,MessageSCCAnalyzer * scc)231 std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
232                                                   const Options& options,
233                                                   MessageSCCAnalyzer* scc) {
234 
235   if (field->is_map()) {
236     ABSL_CHECK(
237         !(field->options().lazy() || field->options().unverified_lazy()));
238     return MakeMapGenerator(field, options, scc);
239   }
240   if (field->is_repeated()) {
241     ABSL_CHECK(!field->options().unverified_lazy());
242 
243     switch (field->cpp_type()) {
244       case FieldDescriptor::CPPTYPE_MESSAGE:
245         return MakeRepeatedMessageGenerator(field, options, scc);
246       case FieldDescriptor::CPPTYPE_STRING: {
247         if (field->cpp_string_type() == FieldDescriptor::CppStringType::kView) {
248           return MakeRepeatedStringViewGenerator(field, options, scc);
249         } else {
250           return MakeRepeatedStringGenerator(field, options, scc);
251         }
252       }
253       case FieldDescriptor::CPPTYPE_ENUM:
254         return MakeRepeatedEnumGenerator(field, options, scc);
255       default:
256         return MakeRepeatedPrimitiveGenerator(field, options, scc);
257     }
258   }
259 
260   if (field->real_containing_oneof() &&
261       field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
262     return MakeOneofMessageGenerator(field, options, scc);
263   }
264 
265   switch (field->cpp_type()) {
266     case FieldDescriptor::CPPTYPE_MESSAGE:
267       return MakeSinguarMessageGenerator(field, options, scc);
268     case FieldDescriptor::CPPTYPE_ENUM:
269       return MakeSinguarEnumGenerator(field, options, scc);
270     case FieldDescriptor::CPPTYPE_STRING: {
271       switch (field->cpp_string_type()) {
272         case FieldDescriptor::CppStringType::kView:
273           return MakeSingularStringViewGenerator(field, options, scc);
274         case FieldDescriptor::CppStringType::kCord:
275           if (field->type() == FieldDescriptor::TYPE_BYTES) {
276             if (field->real_containing_oneof()) {
277               return MakeOneofCordGenerator(field, options, scc);
278             } else {
279               return MakeSingularCordGenerator(field, options, scc);
280             }
281           }
282           ABSL_FALLTHROUGH_INTENDED;
283         default:
284           return MakeSinguarStringGenerator(field, options, scc);
285       }
286     }
287     default:
288       return MakeSinguarPrimitiveGenerator(field, options, scc);
289   }
290 }
291 
HasBitVars(const FieldDescriptor * field,const Options & opts,absl::optional<uint32_t> idx,std::vector<Sub> & vars)292 void HasBitVars(const FieldDescriptor* field, const Options& opts,
293                 absl::optional<uint32_t> idx, std::vector<Sub>& vars) {
294   if (!idx.has_value()) {
295     vars.emplace_back(Sub("set_hasbit", "").WithSuffix(";"));
296     vars.emplace_back(Sub("clear_hasbit", "").WithSuffix(";"));
297     return;
298   }
299 
300   ABSL_CHECK(internal::cpp::HasHasbit(field));
301 
302   int32_t index = *idx / 32;
303   std::string mask = absl::StrFormat("0x%08xu", 1u << (*idx % 32));
304 
305   absl::string_view has_bits = IsMapEntryMessage(field->containing_type())
306                                    ? "_has_bits_"
307                                    : "_impl_._has_bits_";
308 
309   auto has = absl::StrFormat("%s[%d] & %s", has_bits, index, mask);
310   auto set = absl::StrFormat("%s[%d] |= %s;", has_bits, index, mask);
311   auto clr = absl::StrFormat("%s[%d] &= ~%s;", has_bits, index, mask);
312 
313   vars.emplace_back("has_hasbit", has);
314   vars.emplace_back(Sub("set_hasbit", set).WithSuffix(";"));
315   vars.emplace_back(Sub("clear_hasbit", clr).WithSuffix(";"));
316 }
317 
InlinedStringVars(const FieldDescriptor * field,const Options & opts,absl::optional<uint32_t> idx,std::vector<Sub> & vars)318 void InlinedStringVars(const FieldDescriptor* field, const Options& opts,
319                        absl::optional<uint32_t> idx, std::vector<Sub>& vars) {
320   if (!IsStringInlined(field, opts)) {
321     ABSL_CHECK(!idx.has_value());
322     return;
323   }
324 
325   // The first bit is the tracking bit for on demand registering ArenaDtor.
326   ABSL_CHECK_GT(*idx, 0u)
327       << "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking";
328 
329   int32_t index = *idx / 32;
330   std::string mask = absl::StrFormat("0x%08xu", 1u << (*idx % 32));
331   vars.emplace_back("inlined_string_index", index);
332   vars.emplace_back("inlined_string_mask", mask);
333 
334   absl::string_view array = IsMapEntryMessage(field->containing_type())
335                                 ? "_inlined_string_donated_"
336                                 : "_impl_._inlined_string_donated_";
337 
338   vars.emplace_back("inlined_string_donated",
339                     absl::StrFormat("(%s[%d] & %s) != 0;", array, index, mask));
340   vars.emplace_back("donating_states_word",
341                     absl::StrFormat("%s[%d]", array, index));
342   vars.emplace_back("mask_for_undonate", absl::StrFormat("~%s", mask));
343 }
344 }  // namespace
345 
FieldGenerator(const FieldDescriptor * field,const Options & options,MessageSCCAnalyzer * scc_analyzer,absl::optional<uint32_t> hasbit_index,absl::optional<uint32_t> inlined_string_index)346 FieldGenerator::FieldGenerator(const FieldDescriptor* field,
347                                const Options& options,
348                                MessageSCCAnalyzer* scc_analyzer,
349                                absl::optional<uint32_t> hasbit_index,
350                                absl::optional<uint32_t> inlined_string_index)
351     : impl_(MakeGenerator(field, options, scc_analyzer)),
352       field_vars_(FieldVars(field, options)),
353       tracker_vars_(MakeTrackerCalls(field, options)),
354       per_generator_vars_(impl_->MakeVars()) {
355   HasBitVars(field, options, hasbit_index, field_vars_);
356   InlinedStringVars(field, options, inlined_string_index, field_vars_);
357 }
358 
Build(const Options & options,MessageSCCAnalyzer * scc,absl::Span<const int32_t> has_bit_indices,absl::Span<const int32_t> inlined_string_indices)359 void FieldGeneratorTable::Build(
360     const Options& options, MessageSCCAnalyzer* scc,
361     absl::Span<const int32_t> has_bit_indices,
362     absl::Span<const int32_t> inlined_string_indices) {
363   // Construct all the FieldGenerators.
364   fields_.reserve(static_cast<size_t>(descriptor_->field_count()));
365   for (const auto* field : internal::FieldRange(descriptor_)) {
366     size_t index = static_cast<size_t>(field->index());
367     absl::optional<uint32_t> has_bit_index;
368     if (!has_bit_indices.empty() && has_bit_indices[index] >= 0) {
369       has_bit_index = static_cast<uint32_t>(has_bit_indices[index]);
370     }
371 
372     absl::optional<uint32_t> inlined_string_index;
373     if (!inlined_string_indices.empty() && inlined_string_indices[index] >= 0) {
374       inlined_string_index =
375           static_cast<uint32_t>(inlined_string_indices[index]);
376     }
377 
378     fields_.push_back(FieldGenerator(field, options, scc, has_bit_index,
379                                      inlined_string_index));
380   }
381 }
382 
383 }  // namespace cpp
384 }  // namespace compiler
385 }  // namespace protobuf
386 }  // namespace google
387